React中useEffect钩子

  • 副作用:渲染以外的操作:像后端获取数据、操作DOM
  • 参数:副作用方法、依赖(改变时重新执行)
  • 调用时间:渲染JSX之后/依赖改变

useEffect 是 React 中的一个 Hook,用于在函数组件中执行副作用操作。副作用操作包括数据获取、订阅或手动更改 React 组件中的 DOM 等。useEffect 使得在函数组件中处理这些操作变得简单而强大。

基本用法

useEffect 接受一个函数和一个依赖数组作为参数。当依赖数组中的任何值发生变化时,该函数将被重新执行。如果没有提供依赖数组,则该函数将在每次渲染后执行。

复制代码
import React, { useState, useEffect } from 'react';  
  
function Example() {  
  const [count, setCount] = useState(0);  
  
  useEffect(() => {  
    // 副作用操作  
    document.title = `You clicked ${count} times`;  
  
    // 清理函数(可选)  
    return () => {  
      // 组件卸载或依赖项变化前执行的清理操作  
      console.log('Clean up');  
    };  
  }, [count]); // 只有当 count 变化时,副作用操作才会重新执行  
  
  return (  
    <div>  
      <p>You clicked {count} times</p>  
      <button onClick={() => setCount(count + 1)}>  
        Click me  
      </button>  
    </div>  
  );  
}

详解

  1. 副作用函数
    • useEffect 第一个参数是一个函数,该函数中包含了所有副作用操作。
    • 这些操作可以是数据获取、订阅外部数据源、手动操作 DOM 等。
  2. 依赖数组
    • 第二个参数是一个依赖数组(依赖项)。
    • 当数组中的某个依赖项发生变化时,副作用函数会重新执行。
    • 如果省略这个数组,副作用函数会在每次渲染后执行。
  3. 清理函数
    • 副作用函数可以返回一个函数,这个函数会在组件卸载或下次副作用执行前执行。
    • 常用于取消订阅、清除计时器、还原之前的手动 DOM 操作等。
  4. 空依赖数组
    • 如果依赖数组为空 [],则副作用函数只会在组件挂载和卸载时执行一次。
    • 这类似于类组件中的 componentDidMountcomponentWillUnmount
  5. 多个 useEffect
    • 你可以在一个组件中使用多个 useEffect 来分离不同的副作用逻辑。
    • 每个 useEffect 都可以有自己的依赖数组和清理函数。

注意事项

  • 避免在副作用函数中直接修改状态
    • 副作用函数应该只包含副作用操作,如数据获取、订阅等。
    • 状态更新应该通过事件处理函数或其他 React 机制来进行。
  • 确保清理函数无副作用
    • 清理函数中的操作应该是幂等的,即多次执行相同操作不会改变状态或导致错误。
  • 依赖项要准确
    • 确保依赖数组包含所有影响副作用函数行为的变量,以避免不必要的副作用执行。

示例

以下是一个包含多个 useEffect 的示例,分别处理数据获取和手动 DOM 操作:

复制代码
import React, { useState, useEffect } from 'react';  
  
function DataFetcher() {  
  const [data, setData] = useState(null);  
  const [input, setInput] = useState('');  
  
  useEffect(() => {  
    // 数据获取副作用  
    fetch(`https://api.example.com/data?query=${input}`)  
      .then(response => response.json())  
      .then(result => setData(result))  
      .catch(error => console.error('Error fetching data:', error));  
  }, [input]); // 仅在 input 变化时重新获取数据  
  
  useEffect(() => {  
    // 手动 DOM 操作副作用  
    const element = document.getElementById('focusElement');  
    if (element) {  
      element.focus();  
    }  
  
    // 清理函数  
    return () => {  
      if (element) {  
        element.blur();  
      }  
    };  
  }, []); // 只在组件挂载和卸载时执行  
  
  return (  
    <div>  
      <input  
        type="text"  
        value={input}  
        onChange={e => setInput(e.target.value)}  
        placeholder="Search..."  
      />  
      {data ? (  
        <div>  
          <h1>{data.title}</h1>  
          <p>{data.description}</p>  
          <input id="focusElement" type="text" placeholder="Auto-focused" />  
        </div>  
      ) : (  
        <p>Loading...</p>  
      )}  
    </div>  
  );  
}

useEffect 是 React 函数组件中的一个 Hook,用于执行副作用操作。副作用操作是那些不在 React 渲染过程中的操作,比如数据获取、订阅外部数据源、手动更改 DOM 等。useEffect 使得在函数组件中处理这些操作变得简单而强大。

useEffect 的基本用法

useEffect 接受一个函数(副作用函数)和一个依赖数组作为参数。当依赖数组中的任何值发生变化时,副作用函数会重新执行。如果省略依赖数组,副作用函数会在每次组件渲染后都执行。

复制代码
useEffect(() => {  
  // 副作用操作  
  return () => {  
    // 清理操作(可选)  
  };  
}, [dependency1, dependency2, ...]); // 依赖数组

依赖数组

依赖数组是 useEffect 的第二个参数,它是一个包含依赖项的数组。这些依赖项通常是组件的状态变量或 props。当数组中的任何一个依赖项发生变化时,React 会重新调用 useEffect 中的副作用函数。

  • 如果依赖数组为空[]),则副作用函数只会在组件挂载(componentDidMount 等效)和卸载(componentWillUnmount 等效)时执行一次。
  • 如果依赖数组包含状态变量或 props,则每当这些依赖项变化时,副作用函数会重新执行。

注意事项

  • 副作用函数内部不应该直接修改状态或触发其他副作用,因为这可能会导致无限循环或其他难以调试的问题。状态更新应该通过事件处理函数或其他 React 机制来进行。
  • 清理函数(useEffect 返回的函数)用于在副作用函数执行完毕后进行清理操作,比如取消订阅、清除计时器等。它会在组件卸载或下次副作用执行前执行。
  • 依赖数组应该包含所有影响副作用函数行为的变量,以避免不必要的副作用执行。

示例

以下是一个使用 useEffect 和依赖数组的示例,用于在组件挂载时获取数据,并在数据变化时更新 UI

复制代码
import React, { useState, useEffect } from 'react';  
  
function DataFetcher() {  
  const [data, setData] = useState(null);  
  const [query, setQuery] = useState('');  
  
  useEffect(() => {  
    // 数据获取副作用  
    fetch(`https://api.example.com/data?query=${query}`)  
      .then(response => response.json())  
      .then(result => setData(result))  
      .catch(error => console.error('Error fetching data:', error));  
  }, [query]); // 依赖数组包含 query,当 query 变化时重新获取数据  
  
  return (  
    <div>  
      <input  
        type="text"  
        value={query}  
        onChange={e => setQuery(e.target.value)}  
        placeholder="Search..."  
      />  
      {data ? (  
        <div>  
          <h1>{data.title}</h1>  
          <p>{data.description}</p>  
        </div>  
      ) : (  
        <p>Loading...</p>  
      )}  
    </div>  
  );  
}
相关推荐
牛蛙点点申请出战26 分钟前
IconFontViewer -- 一个可以在 Android Studio 中实时预览 IconFont 的插件
android·前端·intellij idea
空中海28 分钟前
03 渲染机制、性能优化与现代 React
javascript·react.js·性能优化
ChalesXavier1 小时前
Fetch API 的基本用法
javascript
是上好佳佳佳呀1 小时前
【前端(十三)】JavaScript 数组与字符串笔记
前端·javascript·笔记
巴沟旮旯儿1 小时前
vite项目配置文件和打包
前端·设计模式
彩票管理中心秘书长1 小时前
Pinia 插件架构与组合式函数:如何让你的 Store 长出“超能力”
前端
彩票管理中心秘书长1 小时前
Pinia 比 Vuex 强在哪?我用同一个模块写了两种实现,你自己看
前端
yingyima1 小时前
用 Cron 加 Webhook 打通自动化工作的任督二脉
前端
JackieDYH1 小时前
CSS Flexbox 与 Grid 的默认行为-布局的底层机制
前端·css·html