当前位置: 首页 > news >正文

react useEffect Hook讲解

什么是 useEffect Hook?

useEffect 是 React 中的一个 Hook,用于在函数组件中处理副作用(side effects)。副作用是指那些不在组件渲染过程中直接发生的事情,比如:

  • 发起网络请求(比如从服务器获取数据)
  • 操作 DOM(比如改变页面标题)
  • 设置定时器(比如 setTimeout 或 setInterval)
  • 订阅外部数据源(比如 WebSocket)

简单来说,useEffect 让你在组件渲染后(或某些特定时机)执行一些额外的操作。

useEffect 的基本语法

useEffect 是一个函数,接收两个参数:

  1. 回调函数:定义你要执行的副作用逻辑。
  2. 依赖数组(可选):控制副作用何时运行。

基本结构如下:

import { useEffect } from 'react';function MyComponent() {useEffect(() => {// 这里写副作用代码console.log('副作用执行了!');}, [/* 依赖项 */]);return <div>我的组件</div>;
}
  • 回调函数:每次组件渲染后(或依赖项变化时),这里面的代码会运行。
  • 依赖数组:告诉 React 什么时候需要重新运行回调函数。如果不传依赖数组,副作用每次渲染都会运行。

useEffect 的三种运行时机

根据依赖数组的不同,useEffect 的运行时机有以下三种情况:

1. 没有依赖数组

如果不提供依赖数组,副作用会在每次组件渲染后都运行。

useEffect(() => {console.log('组件每次渲染都会运行我!');
});

适用场景:很少用,因为每次渲染都运行副作用可能会导致性能问题。

2. 空依赖数组 []

如果提供一个空的依赖数组,副作用只在组件首次渲染后运行一次,类似于类组件中的 componentDidMount。

useEffect(() => {console.log('我只在组件首次渲染时运行!');
}, []);

适用场景

  • 初始化时获取数据(比如从 API 加载数据)
  • 设置一次性的事件监听器

3. 有依赖项的数组 [dep1, dep2, ...]

如果依赖数组中有变量,副作用会在组件首次渲染以及依赖项发生变化时运行。

import { useState, useEffect } from 'react';function MyComponent() {const [count, setCount] = useState(0);useEffect(() => {console.log(`count 变了,现在是 ${count}`);}, [count]);return (<div><p>计数: {count}</p><button onClick={() => setCount(count + 1)}>加1</button></div>);
}

运行逻辑

  • 首次渲染时,useEffect 运行。
  • 每次 count 变化时,useEffect 再次运行。
  • 如果 count 没变,即使组件重新渲染,useEffect 也不会运行。

适用场景

  • 根据状态或 props 变化执行副作用(比如根据用户 ID 获取用户信息)

useEffect 的清理函数

有时候,副作用需要清理,比如清除定时器、取消网络请求或移除事件监听器。useEffect 的回调函数可以返回一个清理函数,在组件卸载或副作用重新运行前执行。

useEffect(() => {const timer = setInterval(() => {console.log('计时器运行中...');}, 1000);// 返回清理函数return () => {clearInterval(timer);console.log('计时器被清理了!');};
}, []);

清理函数的运行时机

  • 组件卸载时(类似于 componentWillUnmount)。
  • 如果有依赖数组,依赖项变化导致副作用重新运行前,清理函数会先执行。

适用场景

  • 清除定时器(setTimeout、setInterval)
  • 取消订阅(比如 WebSocket 或事件监听器)
  • 防止内存泄漏

常见使用场景

以下是一些 useEffect 的典型例子,帮助你理解它的实际用途。

1. 获取数据(API 请求)

import { useState, useEffect } from 'react';function UserList() {const [users, setUsers] = useState([]);useEffect(() => {fetch('https://api.example.com/users').then(response => response.json()).then(data => setUsers(data));}, []); // 空数组,只在首次渲染时请求return (<ul>{users.map(user => (<li key={user.id}>{user.name}</li>))}</ul>);
}

2. 动态更新页面标题

import { useState, useEffect } from 'react';function Counter() {const [count, setCount] = useState(0);useEffect(() => {document.title = `你点击了 ${count} 次`;}, [count]); // 依赖 count,每次 count 变化更新标题return (<div><p>计数: {count}</p><button onClick={() => setCount(count + 1)}>加1</button></div>);
}

3. 设置事件监听器

import { useEffect } from 'react';function WindowSize() {useEffect(() => {const handleResize = () => {console.log(`窗口大小: ${window.innerWidth} x ${window.innerHeight}`);};window.addEventListener('resize', handleResize);// 清理事件监听器return () => {window.removeEventListener('resize', handleResize);};}, []); // 空数组,只在首次渲染时设置监听器return <div>调整窗口大小试试!</div>;
}

注意事项(新手常见坑)

  1. 不要在 useEffect 中直接修改状态,可能导致无限循环

    useEffect(() => {setCount(count + 1); // 错误!会导致无限渲染
    }, [count]);
    

    解决办法:确保状态更新有条件控制,或者使用空依赖数组。

  2. 依赖数组要包含所有用到的变量 如果 useEffect 里的代码用到了某个状态或 props,但没在依赖数组中声明,可能会导致 bug。ESLint 的 react-hooks/exhaustive-deps 规则会帮你检查。

    useEffect(() => {console.log(count); // count 必须在依赖数组中
    }, [count]); // 正确
    
  3. 清理函数的重要性 如果不清理定时器或事件监听器,可能会导致内存泄漏,尤其是在组件频繁挂载/卸载时。

  4. 不要把 useEffect 当成普通函数 useEffect 是为副作用设计的,不要用它来处理渲染逻辑(比如直接修改 DOM 或计算值)。渲染逻辑应该放在组件函数体或 useMemo 中。

总结

  • useEffect 的作用:处理副作用,比如数据获取、DOM 操作、事件监听等。
  • 运行时机
    • 无依赖数组:每次渲染都运行。
    • 空数组 []:仅首次渲染运行。
    • 有依赖项 [dep1, dep2]:首次渲染 + 依赖项变化时运行。
  • 清理函数:返回一个函数来清理副作用,防止内存泄漏。
  • 常见场景:API 请求、更新标题、设置定时器或事件监听器。
http://www.hskmm.com/?act=detail&tid=19196

相关文章:

  • SentinelOne与MITRE ATTCK企业版2025评估的深度解析
  • 详细介绍:Docker的介绍
  • gen-ui-python
  • SPI和普通设计模式区别
  • 2025国内裱纸机厂家最新推荐排行榜:聚焦智能高速与全自动机型,权威精选综合实力 TOP3 厂家
  • 【题解】P13345 [EGOI 2025] IMO
  • 2025电线电缆厂家最新权威推荐榜:聚焦电线电缆实力企业,覆盖多场景需求助力精准选购
  • 9.27课后作业
  • 调度算法,上古三算法
  • 2025 年电脑租赁公司最新推荐排行榜:深度解析 TOP3 优质租电脑公司,助企业个人租赁电脑选择指南
  • 完整教程:✨WPF编程基础【1.2】:XAML中的属性
  • 学位论文中 公式的插入,格式调整、编号以及引用
  • 2025 北京羊蝎子餐厅推荐排行榜:TOP3最新必吃榜单,聚焦朝阳昌平东城等区域,揭秘北京羊蝎子餐厅必吃的门店!
  • 复刻江协激光触发器
  • Eurocrypt 2021 s Accepted Papers
  • Linux云服务器如何手动配置DNS?
  • Python 输入、输出的用法
  • 第一章——概论 - AlgosEng
  • 劝娃妈和娃不要学老人坐姿有感:老人无奈才坐成那样的。。AI协助分析很到位
  • 使用JOL查看对象布局
  • 集训队互测投题——封印
  • 一天一款实用的AI工具,第4期,AI翻译成英语
  • Docker基础与工程部署
  • 安装MariaDB服务器流程介绍在Ubuntu 22.04系统
  • 三种神器让LLM输出结构化数据:LangChain、LlamaIndex与Function Calling实战指南
  • win11安装ensp
  • 自己湿热内蕴出汗痒和岳母生病2天不洗澡发痒的不同-完美解释小孩为啥没那么容易痒
  • vue: ubuntu安装vue环境
  • golang实现ai聊天窗口
  • 源码反码补码