DrillLab
第 78 / 105 道78 / 105 · #332

什么是 StrictMode

What is React strict mode

先自己答,再往下看Answer it yourself first

一句话:一个只在开发模式生效的检查工具组件,通过故意多做一次来暴露不安全的写法。生产构建里它什么都不做。

它做三件事:

  • 渲染函数调用两次—— 暴露渲染过程中的副作用(改了外部变量、直接 mutate props)。因为 render 阶段可能被中断重跑(见 #353),所以它必须是纯的。
  • React 18 起:effect 会「挂载 → 卸载 → 再挂载」——专门暴露「没写清理函数」的 effect。如果你的组件挂两次就出问题(重复订阅、定时器翻倍),那就是真 bug。
  • 警告废弃 API 和过时的 ref 写法。

最重要的一句:「双重渲染导致的问题」不是 StrictMode 的问题,是你的代码的问题。很多人第一反应是「关掉它」—— 正确反应是修好副作用。

会追问:「日志被打印两次正常吗?」—— 开发模式下正常,因为渲染函数被调了两次;生产不会。
「请求被发两次呢?」—— 开发模式下这是预期行为:StrictMode 让 effect 先挂载、卸载、再挂载,清理写对了也会发两次。要检查的是结果:写了 ignore 标志或abort 时,第一次的结果会被丢掉或请求被取消,界面只用第二次的结果;没写清理,才会出现两次结果都写进 state、以及竞态。我们那道 fetch 变式题里ignore 标志 +abort 的写法,正好让它在 StrictMode 下也表现正确。

In one line: a checking component that only does anything in development, and it exposes unsafe code by deliberately doing things twice. In a production build it does nothing.

It does three things:

  • Calls your render function twice — which surfaces side effects during render (mutating an outer variable, mutating props directly). Because the render phase can be interrupted and re-run (see #353), it has to be pure.
  • Since React 18: effects run mount, unmount, mount — specifically to expose effects with no cleanup function. If mounting twice breaks your component (a duplicated subscription, a doubled timer), that is a real bug.
  • Warns about deprecated APIs and legacy ref patterns.

The most important sentence: a problem caused by double rendering is not StrictMode’s problem, it is your code’s. Most people’s first instinct is to turn it off — the right instinct is to fix the side effect.

Follow-up: “Is it normal for my log to print twice?” — yes in development, because the render function ran twice; it will not in production.
“What about my request firing twice?” — in development that is expected: StrictMode mounts, unmounts and remounts the effect, so even correct cleanup sends two requests. What you check is the outcome: with an ignore flag or abort, the first result is discarded or the request is cancelled and the UI uses only the second; without cleanup both results land in state and races appear. The ignore flag plus abort pattern from our fetch variant is exactly what makes it behave correctly under StrictMode too.