useEffect
面试速答(30 秒版 TL;DR)
useEffect用于处理 副作用(side effects),也就是“渲染完成后再做的事”。- 常见副作用有:发请求、订阅事件、开启定时器、操作非 React 管理的外部系统。
- React 18 里要重点记两句:
- Effect 默认在提交到 DOM 之后执行
- 开发环境
StrictMode下会额外执行一次挂载清理流程来帮你发现副作用问题
- 面试里不要把
useEffect说成“生命周期翻版”,它更准确是“把渲染和副作用同步起来”的机制。
1. 什么叫副作用
所谓副作用,就是“不只是根据 props/state 计算 UI”的行为,例如:
- 请求接口
- 订阅 WebSocket / DOM 事件
- 操作定时器
- 手动改标题
document.title
这些事情不能直接塞进 render,因为 render 应该尽量保持纯。
2. 基本用法
useEffect(() => {
const id = setInterval(() => {
console.log('tick')
}, 1000)
return () => clearInterval(id)
}, [])
可以把它拆成两部分理解:
- effect 函数:建立副作用
- cleanup 函数:清理副作用
3. 依赖数组怎么理解
3.1 不传依赖数组
useEffect(() => {
console.log('每次渲染后都执行')
})
每次提交后都执行。
3.2 传空数组 []
useEffect(() => {
console.log('初次挂载后执行')
}, [])
语义上接近“挂载后执行一次”,但 React 18 开发环境的 StrictMode 里会额外做一次检查流程,所以不要把它机械等同于传统 componentDidMount。
3.3 传具体依赖
useEffect(() => {
fetchUser(userId)
}, [userId])
只有依赖变化后,effect 才会重新同步。
4. React 18 的关键变化和面试点
4.1 StrictMode 开发环境双调用
React 18 开发环境下,挂载阶段可能经历:
- 执行 effect
- 立刻 cleanup
- 再执行一次 effect
目的不是线上重复执行,而是帮助你发现:
- cleanup 不完整
- 重复订阅
- 非幂等副作用
4.2 不要用它“推导状态”
下面这种写法常常是不必要的:
useEffect(() => {
setFullName(firstName + lastName)
}, [firstName, lastName])
如果值能直接从当前 state/props 计算出来,优先在 render 阶段直接算,而不是再开一个 effect。
5. 常见场景
5.1 请求数据
useEffect(() => {
let cancelled = false
async function load() {
const data = await fetchUser(userId)
if (!cancelled) setUser(data)
}
load()
return () => {
cancelled = true
}
}, [userId])
5.2 订阅与解绑
- DOM 事件
- WebSocket
- 第三方库实例
核心原则:建立什么,就清理什么。
6. 面试高频答法
Q1:useEffect 和 useLayoutEffect 的区别?
useEffect:DOM 提交后,通常在浏览器绘制之后异步执行,更适合大多数副作用useLayoutEffect:DOM 提交后、浏览器绘制前同步执行,适合测量布局或避免闪烁
Q2:为什么依赖数组里要写全?
因为 effect 要和它用到的响应式值保持同步。依赖漏写,最常见的问题就是:
- 闭包读到旧值
- 副作用没有按预期更新
Q3:为什么说“能不用 effect 就不用”?
因为 effect 是和外部系统同步的手段,不是通用业务逻辑收纳箱。很多“状态推导”或“事件响应”其实可以直接写在:
- render 计算中
- 事件处理函数里
常见追问
1)cleanup 什么时候执行?
- 下一次 effect 执行前
- 组件卸载时
2)请求一定要写在 useEffect 吗?
客户端拉取场景通常会放在 effect,但框架化场景下也可能前移到 loader、server component、路由层数据获取。
易错点/坑
- 把
useEffect当“生命周期替代品”机械背诵。 - 用 effect 推导纯计算状态。
- 依赖漏写,导致闭包陈旧。
- 忘记 cleanup,造成重复订阅和内存泄漏。
速记要点(可背诵)
useEffect:渲染完成后同步外部副作用。- React 18 开发环境
StrictMode会额外跑一轮挂载清理流程。 - 原则:能在 render 算的别进 effect,建立副作用就要成对清理。