2024-06-22  2024-09-18    1038 字  3 分钟

一个参数

useEffect()本身是一个函数,由 React 框架提供,在函数组件内部调用即可。

举例来说,我们希望组件加载以后,网页标题(document.title)会随之改变。那么,改变网页标题这个操作,就是组件的副效应,必须通过useEffect()来实现。

1import React, { useEffect } from 'react';
2
3function Welcome(props) {
4  useEffect(() => {
5    document.title = '加载完成';
6  });
7  return <h1>Hello, {props.name}</h1>;
8}

上面例子中,useEffect()的参数是一个函数,它就是所要完成的副效应(改变网页标题)。组件加载以后,React 就会执行这个函数。(查看运行结果)

useEffect()的作用就是指定一个副效应函数,组件每渲染一次,该函数就自动执行一次。组件首次在网页 DOM 加载后,副效应函数也会执行。

两个参数

有时候,我们不希望useEffect()每次渲染都执行,这时可以使用它的第二个参数,使用一个数组指定副效应函数的依赖项,只有依赖项发生变化,才会重新渲染。

1function Welcome(props) {
2  useEffect(() => {
3    document.title = `Hello, ${props.name}`;
4  }, [props.name]);
5  return <h1>Hello, {props.name}</h1>;
6}

上面例子中,useEffect()的第二个参数是一个数组,指定了第一个参数(副效应函数)的依赖项(props.name)。只有该变量发生变化时,副效应函数才会执行。

如果第二个参数是一个空数组,就表明副效应参数没有任何依赖项。因此,副效应函数这时只会在组件加载进入 DOM 后执行一次,后面组件重新渲染,就不会再次执行。这很合理,由于副效应不依赖任何变量,所以那些变量无论怎么变,副效应函数的执行结果都不会改变,所以运行一次就够了。

只运行一次

只需要在第二个参数传入空即可在页面加载后只执行一次

1function Welcome(props) {
2  useEffect(() => {
3    document.title = `Hello, ${props.name}`;
4  }, []);
5  return <h1>Hello, {props.name}</h1>;
6}

返回值

副效应是随着组件加载而发生的,那么组件卸载时,可能需要清理这些副效应。

useEffect()允许返回一个函数,在组件卸载时,执行该函数,清理副效应。如果不需要清理副效应,useEffect()就不用返回任何值。

1useEffect(() => {
2  const subscription = props.source.subscribe();
3  return () => {
4    subscription.unsubscribe();
5  };
6}, [props.source]);

上面例子中,useEffect()在组件加载时订阅了一个事件,并且返回一个清理函数,在组件卸载时取消订阅。

实际使用中,由于副效应函数默认是每次渲染都会执行,所以清理函数不仅会在组件卸载时执行一次,每次副效应函数重新执行之前,也会执行一次,用来清理上一次渲染的副效应。

注意

如果有多个副效应,应该调用多个useEffect(),而不应该合并写在一起。

 1function App() {
 2  const [varA, setVarA] = useState(0);
 3  const [varB, setVarB] = useState(0);
 4
 5  useEffect(() => {
 6    const timeout = setTimeout(() => setVarA(varA + 1), 1000);
 7    return () => clearTimeout(timeout);
 8  }, [varA]);
 9
10  useEffect(() => {
11    const timeout = setTimeout(() => setVarB(varB + 2), 2000);
12
13    return () => clearTimeout(timeout);
14  }, [varB]);
15
16  return <span>{varA}, {varB}</span>;
17}

除另有声明外本博客文章均采用 知识共享 (Creative Commons) 署名 4.0 国际许可协议 进行许可转载请注明原作者与文章出处