React useEffect Hooks(钩子)

useEffect 钩子允许您在组件中执行副作用。副作用的一些示例包括:获取数据、直接更新 DOM 和计时器。

useEffect 接受两个参数。第二个参数是可选的。

useEffect(<function>,<dependency>)

让我们以计时器为例。

实例:

使用 setTimeout() 计算初始渲染后的 1 秒数:

  1. import { useState, useEffect } from "react";
  2. import ReactDOM from "react-dom";
  3. function Timer() {
  4. const [count, setCount] = useState(0);
  5. useEffect(() => {
  6. setTimeout(() => {
  7. setCount((count) => count + 1);
  8. }, 1000);
  9. });
  10. return <h2>I have rendered {count} times!</h2>;
  11. }
  12. ReactDOM.render(<Timer />, document.getElementById('root'));

useEffect 在每个渲染上运行。这意味着当计数改变时,会发生渲染,然后触发另一种效果。

这不是我们想要的。有几种方法可以控制副作用何时发生。

我们应该始终包含接受数组的第二个参数。我们可以选择将依赖项传递到此数组中的 useEffect

1. 无传递依赖项:
  1. useEffect(() => {
  2. //Runs on every render
  3. });
2. 一个空数组:
  1. useEffect(() => {
  2. //Runs only on the first render
  3. }, []);
3. Props 或 state 值:
  1. useEffect(() => {
  2. //Runs on the first render
  3. //And any time any dependency value changes
  4. }, [prop, state]);

所以,为了解决这个问题,让我们只在初始渲染时运行这个效果。

实例:

仅在初始渲染时运行效果:

  1. import { useState, useEffect } from "react";
  2. import ReactDOM from "react-dom";
  3. function Timer() {
  4. const [count, setCount] = useState(0);
  5. useEffect(() => {
  6. setTimeout(() => {
  7. setCount((count) => count + 1);
  8. }, 1000);
  9. }, []); // <- add empty brackets here
  10. return <h2>I've rendered {count} times!</h2>;
  11. }
  12. ReactDOM.render(<Timer />, document.getElementById('root'));
实例:

下面是一个依赖变量的 useEffect 钩子的示例。如果 count 变量更新,效果将再次运行:

  1. import { useState, useEffect } from "react";
  2. import ReactDOM from "react-dom";
  3. function Counter() {
  4. const [count, setCount] = useState(0);
  5. const [calculation, setCalculation] = useState(0);
  6. useEffect(() => {
  7. setCalculation(() => count * 2);
  8. }, [count]); // <- add the count variable here
  9. return (
  10. <>
  11. <p>Count: {count}</p>
  12. <button onClick={() => setCount((c) => c + 1)}>+</button>
  13. <p>Calculation: {calculation}</p>
  14. </>
  15. );
  16. }
  17. ReactDOM.render(<Counter />, document.getElementById("root"));

如果存在多个依赖项,则应将它们放在 useEffect 依赖项数组中。


效果清理

有些效果需要清理以减少内存泄漏。

应该处理超时、订阅、事件侦听器和其他不再需要的效果。

我们通过在 useffect 钩子的最后包含一个返回函数来实现这一点。

实例:

清理 useEffect 钩子结束后的计时器

  1. import { useState, useEffect } from "react";
  2. import ReactDOM from "react-dom";
  3. function Timer() {
  4. const [count, setCount] = useState(0);
  5. useEffect(() => {
  6. let timer = setTimeout(() => {
  7. setCount((count) => count + 1);
  8. }, 1000);
  9. return () => clearTimeout(timer)
  10. }, []);
  11. return <h2>I've rendered {count} times!</h2>;
  12. }
  13. ReactDOM.render(<Timer />, document.getElementById("root"));
注意:要清理计时器,我们必须给它命名。

分类导航