元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
React基础
▶
环境搭建
使用Create React App
Webpack基础配置
Babel转换配置
▶
JSX核心
JSX语法基础
JSX表达式使用
JSX与HTML差异
▶
组件入门
函数组件编写
类组件结构
组件组合模式
▶
核心概念
▶
Props机制
Props传递与接收
PropTypes类型检查
默认Props设置
▶
State管理
useState使用
setState机制
状态提升
▶
生命周期
类组件生命周期
useEffect使用
依赖项数组作用
▶
进阶实践
▶
路由管理
React Router安装
基本路由配置
动态路由参数
▶
状态管理
Context API使用
Redux核心概念
Redux Toolkit实践
▶
性能优化
memo使用
useCallback应用
代码分割实践
发布时间:
2025-03-22 12:58
↑
☰
# useEffect使用 本文将详细介绍React中useEffect Hook的使用方法,帮助你理解如何在函数组件中处理副作用。 ## 什么是useEffect? useEffect是React提供的一个Hook,用于在函数组件中执行副作用操作。副作用包括: 1. 数据获取 2. 订阅设置 3. DOM操作 4. 定时器设置 5. 日志记录 ## 基本语法 ```javascript import React, { useEffect, useState } from 'react'; function Example() { useEffect(() => { // 执行副作用 return () => { // 清理副作用 }; }, [/* 依赖项数组 */]); } ``` ## 基础用法 ### 1. 无依赖项 ```javascript function Timer() { const [count, setCount] = useState(0); useEffect(() => { const timer = setInterval(() => { setCount(c => c + 1); }, 1000); // 清理函数 return () => clearInterval(timer); }); // 没有依赖项数组,每次渲染后都会执行 return <h1>Count: {count}</h1>; } ``` ### 2. 空依赖数组 ```javascript function OnMount() { useEffect(() => { console.log('Component mounted'); return () => console.log('Component will unmount'); }, []); // 空依赖数组,只在挂载和卸载时执行 return <div>Hello World</div>; } ``` ### 3. 有依赖项 ```javascript function DataFetcher({ id }) { const [data, setData] = useState(null); useEffect(() => { let isMounted = true; async function fetchData() { try { const response = await fetch(`api/data/${id}`); const result = await response.json(); if (isMounted) { setData(result); } } catch (error) { if (isMounted) { console.error('Error fetching data:', error); } } } fetchData(); return () => { isMounted = false; }; }, [id]); // 当id变化时重新执行 if (!data) return <div>Loading...</div>; return <div>{data.title}</div>; } ``` ## 常见用例 ### 1. 订阅管理 ```javascript function SubscriptionComponent() { const [data, setData] = useState(null); useEffect(() => { const subscription = dataSource.subscribe(value => { setData(value); }); // 清理订阅 return () => subscription.unsubscribe(); }, []); // 空依赖数组,只在挂载时订阅,卸载时取消订阅 return <div>{data}</div>; } ``` ### 2. DOM操作 ```javascript function AutoFocus() { const inputRef = useRef(null); useEffect(() => { // 组件挂载时自动聚焦 inputRef.current?.focus(); }, []); return <input ref={inputRef} />; } ``` ### 3. 事件监听 ```javascript function WindowWidth() { const [width, setWidth] = useState(window.innerWidth); useEffect(() => { const handleResize = () => setWidth(window.innerWidth); window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); }; }, []); return <div>Window width: {width}px</div>; } ``` ## 高级用法 ### 1. 条件执行 ```javascript function ConditionalEffect({ enabled }) { useEffect(() => { if (!enabled) return; const handler = () => { console.log('Event handled'); }; window.addEventListener('event', handler); return () => window.removeEventListener('event', handler); }, [enabled]); // 只在enabled变化时重新执行 return <div>Conditional Effect Demo</div>; } ``` ### 2. 多个Effect组合 ```javascript function MultipleEffects() { const [count, setCount] = useState(0); const [name, setName] = useState(''); // 处理计数器 useEffect(() => { document.title = `Count: ${count}`; }, [count]); // 处理用户名 useEffect(() => { const savedName = localStorage.getItem('username'); if (savedName) setName(savedName); return () => { localStorage.setItem('username', name); }; }, [name]); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(c => c + 1)}> Increment </button> <input value={name} onChange={e => setName(e.target.value)} placeholder="Enter name" /> </div> ); } ``` ## 常见陷阱 ### 1. 依赖项遗漏 ```javascript function Counter({ step }) { const [count, setCount] = useState(0); // 错误:遗漏step依赖 useEffect(() => { const timer = setInterval(() => { setCount(c => c + step); }, 1000); return () => clearInterval(timer); }, []); // 应该是[step] return <div>Count: {count}</div>; } ``` ### 2. 无限循环 ```javascript function InfiniteLoop() { const [data, setData] = useState([]); // 错误:Effect中更新状态导致无限循环 useEffect(() => { setData([...data, 'new item']); }, [data]); // 正确:使用函数式更新 useEffect(() => { setData(prev => [...prev, 'new item']); }, []); // 或者移除依赖 return <div>{data.join(', ')}</div>; } ``` ### 3. 竞态条件 ```javascript function SearchResults({ query }) { const [results, setResults] = useState([]); useEffect(() => { let isCancelled = false; async function fetchData() { try { const response = await fetch(`api/search?q=${query}`); const data = await response.json(); if (!isCancelled) { setResults(data); } } catch (error) { if (!isCancelled) { console.error('Error:', error); } } } fetchData(); return () => { isCancelled = true; }; }, [query]); return ( <ul> {results.map(item => ( <li key={item.id}>{item.title}</li> ))} </ul> ); } ``` ## 最佳实践 1. 将相关的逻辑分组到不同的Effect中 2. 避免过度使用Effect 3. 正确处理清理函数 4. 使用依赖项检查工具(如eslint-plugin-react-hooks) 5. 考虑使用自定义Hook封装常用的Effect逻辑 ## 性能优化 1. 避免不必要的依赖 2. 使用防抖和节流 3. 使用useCallback和useMemo优化依赖 4. 适当使用条件执行 通过合理使用useEffect,我们可以在函数组件中优雅地处理副作用,使代码更加清晰和可维护。记住要正确处理清理函数,避免内存泄漏,同时注意依赖项的完整性和正确性。