Skip to content

useEffect:页面出现后再去做一件外部工作 ​

一句话理解 ​

组件负责描述页面。Effect 负责在页面显示之后,与组件外面的世界同步,例如请求后端、启动定时器或监听浏览器事件。

类比:你先打开一家店,再安排员工去仓库拿库存表。开店是显示组件,去仓库拿数据是 Effect。

具体场景:打开页面后读取留言 ​

tsx
useEffect(() => {
  loadMessages()
}, [])

逐段读:

text
useEffect       告诉 React:页面显示后安排这项工作
() => { }       要执行的工作,这里调用 loadMessages
[]              依赖列表为空;这段代码不依赖某个会变化的值

loadMessages 可能这样写:

tsx
async function loadMessages() {
  const response = await fetch('/api/messages')
  const data = await response.json()
  setMessages(data)
}

真实过程:页面先出现 → 浏览器发 GET 请求 → 后端查询数据库 → 返回 JSON → setMessages 更新列表 → 页面重新显示。

依赖数组到底是什么 ​

tsx
useEffect(() => {
  loadMessages(userId)
}, [userId])

意思不是“把 userId 传给 Effect”。意思是:第一次显示后执行;以后 userId 变化时再执行。

为什么会不停请求 ​

危险例子:

tsx
useEffect(() => {
  loadMessages()
}, [messages])

如果 loadMessages 最后调用 setMessages,流程会变成:

text
请求完成
→ messages 改变
→ Effect 因 messages 改变再次执行
→ 再请求
→ messages 又改变
→ 继续循环

在 Network 面板看到同一个请求不断出现时,就检查 Effect 的依赖和更新关系。

为什么开发环境偶尔看到两次请求 ​

React 的开发检查模式可能故意多运行一次某些逻辑,帮助发现没有正确清理的副作用。先确认生产构建是否仍然重复,再检查 Effect 是否可以安全执行两次。不要一看到两次就删除所有 Effect。

什么时候不该用 Effect ​

如果只是根据已有值计算另一个值,直接计算通常更清楚:

tsx
const visibleMessages = messages.filter((message) => message.visible)

不需要先建另一个 state,再用 Effect 把它同步过去。

定时器要清理 ​

tsx
useEffect(() => {
  const timer = setInterval(refresh, 10000)
  return () => clearInterval(timer)
}, [])

返回的函数像“下班关灯”:组件离开页面时停止定时器。

自己试试 ​

打开 DevTools 的 Network,刷新一次页面。找到最早出现的业务请求,再回到编辑器搜索它的 URL。确认它是否在 useEffect 调用的函数里,以及依赖数组里写了什么。

Network 里同一个请求不停出现,React 代码里首先检查哪里?

答案:检查发请求的 useEffect 依赖数组,以及请求完成后更新的 state 是否又触发了这个 Effect。

写给想驾驭 AI,而不只是依赖 AI 的 Vibe Coder。