学习React-12-useEffect
纯函数&副函数
纯函数(Pure Function)
同样的输入,必定得到同样的输出,而且执行过程中不修改外部世界。
- 相同输入 → 相同输出(确定性)。
- 无副作用(不依赖、不修改外部状态)。
- 不依赖系统时间、随机数、I/O 等“不稳定”数据。
小栗子
// 纯函数:计算订单折扣价
function getDiscountedPrice(price, rate) {return price * rate; // 只依赖参数,不改外部,无 I/O
}
副函数(Impure Function / Side-effect Function)
执行时会对外部世界“动手脚”——改全局变量、写日志、发请求、改 DOM、读写文件、随机数、获取时间 … 都属于副作用。
- 依赖或修改了外部可变状态。
- 做了I/O(网络、磁盘、控制台)。
- 使用了非确定性数据(Date.now()、Math.random())。
小栗子
// 副函数:把折扣价写进全局变量 + 打印日志
let finalPrice = 0;
function applyDiscount(price, rate) {finalPrice = price * rate; // 改外部console.log('新价格:', finalPrice); // I/Oreturn finalPrice;
}
sueEffect
useEffect 是 React Hook 的核心成员之一,它让函数组件拥有了
生命周期
能力——也就是副作用(side-effect)管理
。
基本用法
语法:
useEffect(effect: () => (void | (() => void | undefined)), deps?: ReadonlyArray<any>)
参数:
- effect: 一个函数,React 会在渲染提交到屏幕后调用它。可以返回一个
(可选)
清理函数(cleanup),组件卸载或依赖变化时会先执行它。 - deps(可选):依赖数组,告诉 React 何时重新运行 effect。当deps里面变量的值发生变化的时候会重新调用effect。
返回值:
let a = useEffect(() => {})
console.log('a', a) //undefined
三种使用模式
依赖数组 | 执行时机 | 对应类生命周期 |
---|---|---|
不传 | 每次渲染后都执行 | componentDidUpdate |
[] | 挂载后执行一次 | componentDidMount |
[a, b] | a 或 b 变化时执行 | 自定义 |
小栗子
① 挂载后发请求(仅一次)
useEffect(() => {fetchUser().then(setUser);
}, []); // 空依赖 → 只运行一次
② 订阅 & 清理
useEffect(() => {const id = setInterval(() => tick(), 1000);return () => clearInterval(id); // 清理函数
}, []);
③ 依赖变化时重新执行
useEffect(() => {document.title = `当前计数:${count}`;
}, [count]); // count 变了就重新执行
小案例
需求: 实现根据用户的输入展示对应的信息。
小工具:https://jsonplaceholder.typicode.com 可以模拟用户数据进行增删查改
import React, { useState, useEffect } from "react"export function EffectDemo() {interface UserData {id: numbername: stringusername: stringphone: stringwebsite: string}const [uid, setUid] = useState(1);const [user, setUser] = useState<UserData | null>(null);const [loading, setLoading] = useState(false);useEffect(() => {setLoading(true)// https://jsonplaceholder.typicode.com 可以模拟数据fetch(`https://jsonplaceholder.typicode.com/users/${uid}`).then(res => res.json()).then(data => { setUser(data); setLoading(false) })}, [uid])return (<div><h1>User Information</h1><input type="text" value={uid === 0 ? '': uid} onChange={(e) => setUid(Number(e.target.value))} /><p>姓名:{user && user.name}</p><p>电话:{user && user.phone}</p><p>网址:{user && user.website}</p><h1>{loading && <span>Loading...</span>}</h1></div>)
}export default EffectDemo;
实现效果:
注意事项
- effect 运行在渲染之后,是
异步
的;不会阻塞浏览器绘制。 - 每次重新执行 effect 前,React 会
先调用
上一次返回的清理函数(如果有)。 - 不要在 effect 里直接 setState 造成死循环;如果必须,请用条件或 useCallback/useRef 控制。
- 依赖数组要“诚实”:用到什么变量就填什么,否则会出现闭包旧值 bug;官方推荐用 eslint-plugin-react-hooks 自动检查。
- 如果真想模拟“挂载 / 卸载”两次调用(React 18
严格模式
+ 开发环境),不要试图绕过
,这是 React 故意暴露潜在内存泄漏的方式。