React的useEffect Hook

159 阅读2分钟

在React函数组件中,useEffect Hook是一个极其强大的工具,它允许我们在函数组件中执行副作用操作(如数据获取、订阅或手动更改React组件中的DOM)。

什么是useEffect?

useEffect是React的一个Hook,它让你在函数组件中执行副作用操作。与类组件中的componentDidMountcomponentDidUpdatecomponentWillUnmount生命周期方法类似,但更加灵活和强大。useEffect可以接受一个函数作为参数,这个函数会在组件渲染到屏幕后执行。此外,你还可以提供一个依赖项数组,以控制副作用函数的执行时机。

基本用法

组件挂载时执行

如果你想要在某个副作用仅在组件挂载到DOM后执行一次,可以将依赖项数组留空([])。

import React, { useEffect } from 'react';  
  
function MyComponent() {  
  useEffect(() => {  
    // 组件挂载后执行  
    console.log('Component mounted!');  
  
    // 注意:这里没有返回值(即没有清理函数)  
  }, []); // 依赖项数组为空,表示只在挂载时执行  
  
  return <div>Hello, World!</div>;  
}

监听值变化

如果副作用依赖于某些值(如props或state),你可以将这些值作为依赖项数组的元素传入useEffect。这样,每当这些值变化时,副作用函数就会重新执行。

import React, { useState, useEffect } from 'react';  
  
function Counter({ initialCount }) {  
  const [count, setCount] = useState(initialCount);  
  
  useEffect(() => {  
    // 当count变化时执行  
    console.log(`Count is: ${count}`);  
  }, [count]); // 依赖项数组包含count  
  
  return (  
    <div>  
      <p>Count: {count}</p>  
      <button onClick={() => setCount(count + 1)}>Increment</button>  
    </div>  
  );  
}

清理操作

当副作用函数执行完毕后,你可能需要执行一些清理操作,比如取消网络请求、移除事件监听器或清除定时器。这时,你可以通过返回一个函数来实现。这个函数会在组件卸载或依赖项变化导致的副作用重新执行前被调用。

import React, { useEffect } from 'react';  
  
function Timer() {  
  useEffect(() => {  
    const timerId = setInterval(() => {  
      console.log('Timer is running...');  
    }, 1000);  
  
    // 返回一个清理函数  
    return () => {  
      clearInterval(timerId);  
      console.log('Timer has been cleared.');  
    };  
  }, []); // 依赖项数组为空,表示只在挂载时设置一次定时器  
  
  return <div>Check the console for timer updates.</div>;  
}

注意: useEffect的返回值函数在以下两种情况下执行:

一、组件卸载时

当组件从 DOM 中被移除(卸载)时,useEffect的返回值函数会被调用。这可以用于清理在副作用中创建的资源,例如取消订阅事件、清除定时器、关闭网络连接等,以避免内存泄漏和资源浪费。

例如:

import React, { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    const intervalId = setInterval(() => {
      console.log('Interval running');
    }, 1000);

    // 返回一个清理函数
    return () => {
      clearInterval(intervalId);
      console.log('Component unmounted, interval cleared.');
    };
  }, []);

  return <div>My Component</div>;
}

在这个例子中,当MyComponent组件卸载时,返回的清理函数会被调用,清除定时器。

二、下一次副作用执行前

如果useEffect的依赖项数组中的某个值发生了变化,导致副作用函数再次执行,那么在新的副作用函数执行之前,上一次副作用的返回值函数会被调用。

例如:

import React, { useState, useEffect } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log(`Count is ${count}`);

    return () => {
      console.log(`Before next effect for count ${count}`);
    };
  }, [count]);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

当点击按钮增加count的值时,在新的副作用函数执行之前,会先调用上一次副作用的返回值函数,输出Before next effect for count [previous value]。然后再输出新的Count is [new value]

总结

useEffect是 React 中一个非常重要的 Hook,它允许我们在函数组件中执行副作用操作。通过合理地使用useEffect和依赖项数组,我们可以控制副作用操作的执行时机,从而提高应用的性能和可维护性。