Skip to content

React 的严格模式 (StrictMode) 有什么作用?

理解 React 严格模式 (StrictMode):它是什么,为什么需要它?

在日常的 React 开发中,我们常常会遇到一些难以追踪的问题,比如意料之外的组件行为、不易察觉的性能瓶颈,或是由旧版 API 埋下的技术债。为了帮助开发者在开发阶段就识别并修复这些潜在问题,React 提供了一个非常有用的工具——严格模式 (StrictMode)。

严格模式 (<React.StrictMode>) 本身不会渲染任何可见的 UI,它更像是一个“代码质检员”,专门为我们的应用开启额外的检查警告。需要强调的是,这些检查只在开发模式下运行,不会影响生产环境的构建,因此我们可以放心使用。

接下来,我们将深入探讨严格模式主要关注哪些方面,以及它如何帮助我们写出更健壮、更现代React 代码。

识别不安全的生命周期方法

随着 React 的演进,一些早期的生命周期方法被认为存在潜在风险,尤其是在未来的并发渲染 (Concurrent Rendering) 模式下。这些方法可能会被多次调用,或者在不合适的时机中断,导致不可预测的行为,例如内存泄漏或状态不一致。

严格模式会重点标记以下这些不安全的生命周期方法:

  • componentWillMount (将被弃用,建议使用 constructor 替代)

  • componentWillReceiveProps (将被弃用,建议使用 static getDerivedStateFromProps 替代)

  • componentWillUpdate (将被弃用,建议使用 getSnapshotBeforeUpdate 替代)

当我们使用了这些方法时,控制台会输出警告,引导我们迁移到更安全、更现代的 API。这不仅是为了兼容未来的 React 版本,更是为了从根本上避免副作用带来的困扰。

警告废弃的 API 使用

除了生命周期方法,严格模式还会检查其他一些已被废弃或不推荐的用法。

  • 旧版的 String Ref API:像 this.refs.myRef 这样的字符串引用方式存在一些问题,例如它无法被静态分析,且在处理动态子组件时显得笨拙。严格模式会推荐我们使用 React.createRef() 或回调形式的 Refs (callback refs),这两种方式都更加灵活和可预测。

  • 旧版的 Context API:在现代 React Context API(React.createContext)出现之前,存在一个实验性的 Context API。它的 API 设计容易出错,且性能不佳。严格模式会检测并警告这种旧版 API 的使用,推动我们采用官方推荐的稳定方案。

检测意外的副作用

React 的理念中,渲染过程应该是“纯粹”的。这意味着对于相同的 propsstate,渲染输出应该总是一致的,并且在这个过程中不应产生任何“副作用”(Side Effects),比如手动修改 DOM、发起网络请求设置定时器

为了帮助我们发现非纯粹的渲染逻辑,严格模式会故意重复调用某些函数,包括:

  • 组件的 constructor

  • render 方法

  • setState 的更新函数 (updater functions)

  • useState, useMemo, useReducerHooks

如果我们的代码在这些函数中包含了副作用,那么在严格模式下,这些副作用会被执行两次。这种“双重调用”机制就像一个压力测试,能立刻暴露那些隐藏在渲染过程中的不当操作,帮助我们将其移至更合适的地方,比如 useEffectcomponentDidMount

提醒废弃的 findDOMNode 用法

findDOMNode 曾被用来获取组件渲染出的底层 DOM 节点。但这种方式破坏了组件的封装性,使得父组件可以直接操作子组件的 DOM,导致重构困难。同时,在 React 的抽象模型中,一个组件也可能不会只渲染一个 DOM 节点(例如,使用 Fragment)。

因此,findDOMNode 正在被逐步废弃。严格模式会警告它的使用,并鼓励我们采用更现代的 Forwarding Refs 方案,将 Ref 从父组件安全地传递到子组件的 DOM 元素上,从而在保持封装性的同时实现必要的 DOM 操作。

如何启用严格模式?

启用严格模式非常简单,我们只需要用 <React.StrictMode> 标签包裹住需要检查的组件树即可。

我们可以将其应用于整个应用:

javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

也可以只针对应用中的特定部分,进行渐进式升级:

javascript
import React from 'react';
import { Header, Footer, Content } from './components';

function App() {
  return (
    <div>
      <Header />
      <React.StrictMode>
        <Content /> 
      </React.StrictMode>
      <Footer />
    </div>
  );
}

总结

总而言之,React 的严格模式是一个纯粹的开发辅助工具。它通过在开发环境中引入一系列额外的检查,帮助我们提前识别出代码中的不安全实践、潜在副作用和已被废弃的 API

将严格模式集成到我们的工作流中,是一种低成本、高回报的投资。它不仅能提升当前代码的质量和稳定性,更能确保我们的应用为 React 未来的并发新特性做好准备,使项目在长期维护中保持健康。

不知道说啥了很无语了