学习React (6) 副作用(side effects)

55 阅读2分钟

在 React 中,副作用(side effects)指的是任何不直接计算组件渲染输出的操作。这些操作通常包括数据获取、订阅、手动更改 DOM 等。React 的 useEffect 钩子允许你在函数组件中执行这些副作用。

什么是更新时执行副作用

当我们说“更新时执行副作用”时,指的是在组件的某些状态或属性发生变化时触发的操作。例如,当组件首次挂载(mount)或者组件的依赖项(dependencies)变化时,执行某些逻辑。具体来说,useEffect 提供了一种机制来执行这些操作。

useEffect 如何工作

useEffect 钩子接收两个参数:

  1. 一个函数,这个函数包含了你希望在副作用发生时执行的代码。
  2. 一个依赖项数组,只有当数组中的某些值发生变化时,React 才会重新运行第一个参数中的函数。

基本示例

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

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

  // useEffect 无依赖项数组,组件每次渲染都会执行
  useEffect(() => {
    console.log('Component re-rendered');
  });

  // useEffect 有空依赖项数组,只在组件挂载和卸载时执行一次
  useEffect(() => {
    console.log('Component mounted');

    return () => {
      console.log('Component will unmount');
    };
  }, []);

  // useEffect 有依赖项数组,在依赖项变化时执行
  useEffect(() => {
    console.log(`Count value changed: ${count}`);
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

详细说明

  1. 组件每次渲染都会执行

    useEffect(() => {
      console.log('Component re-rendered');
    });
    

    如果没有提供依赖项数组,useEffect 将在每次组件渲染时执行。这可能会导致性能问题,通常我们需要控制副作用的执行频率。

  2. 组件挂载和卸载时执行

    useEffect(() => {
      console.log('Component mounted');
    
      return () => {
        console.log('Component will unmount');
      };
    }, []);
    

    提供一个空的依赖项数组,useEffect 只会在组件挂载时执行一次,并且在组件卸载时执行清理函数。在这里,我们模拟了组件的初始化和清理过程。

  3. 依赖项变化时执行

    useEffect(() => {
      console.log(`Count value changed: ${count}`);
    }, [count]);
    

    当依赖项数组中的值(在这个例子中是 count)发生变化时,useEffect 会重新执行。这个功能非常强大,可以用来响应特定状态的变化。

实际应用场景

  1. 数据获取: 在组件首次挂载时,从 API 获取数据。
  2. 订阅: 在组件挂载时订阅某些事件,在组件卸载时取消订阅。
  3. DOM 操作: 在特定状态变化时,手动操作 DOM,例如聚焦某个输入框。

示例:数据获取

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

function DataFetchingComponent() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('https://api.example.com/data');
        const result = await response.json();
        setData(result);
      } catch (error) {
        console.error('Error fetching data:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []); // 空依赖项数组,表示仅在初次挂载时执行

  if (loading) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <h1>Data</h1>
      <ul>
        {data.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}

export default DataFetchingComponent;

在这个示例中,数据获取操作作为副作用在组件挂载时执行,并且只有在组件初次挂载时执行一次,这样就避免了不必要的重复请求。

通过使用 useEffect 钩子,你可以非常灵活地处理各种副作用,并确保它们在适当的时间点执行。希望这些解释和示例能帮助你更好地理解和使用 React 中的副作用管理。