<StrictMode>

<StrictMode> 可让你在开发过程中及早发现组件中的常见错误。

¥<StrictMode> lets you find common bugs in your components early during development.

<StrictMode>
<App />
</StrictMode>

参考

¥Reference

<StrictMode>

使用 StrictMode 为里面的组件树启用额外的开发行为和警告:

¥Use StrictMode to enable additional development behaviors and warnings for the component tree inside:

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';

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

请参阅下面的更多示例。

¥See more examples below.

严格模式启用以下仅限开发的行为:

¥Strict Mode enables the following development-only behaviors:

属性

¥Props

StrictMode 不接受属性。

¥StrictMode accepts no props.

注意事项

¥Caveats

  • <StrictMode> 封装的树中无法选择退出严格模式。这使你确信 <StrictMode> 中的所有组件都已检查。如果两个从事产品工作的团队不同意他们是否认为选中有价值,他们需要达成共识或将 <StrictMode> 在树中向下移动。

    ¥There is no way to opt out of Strict Mode inside a tree wrapped in <StrictMode>. This gives you confidence that all components inside <StrictMode> are checked. If two teams working on a product disagree whether they find the checks valuable, they need to either reach consensus or move <StrictMode> down in the tree.


用法

¥Usage

为整个应用启用严格模式

¥Enabling Strict Mode for entire app

严格模式允许对 <StrictMode> 组件内的整个组件树进行额外的仅开发检查。这些检查可帮助你在开发过程的早期发现组件中的常见错误。

¥Strict Mode enables extra development-only checks for the entire component tree inside the <StrictMode> component. These checks help you find common bugs in your components early in the development process.

要为整个应用启用严格模式,请在渲染时用 <StrictMode> 封装根组件:

¥To enable Strict Mode for your entire app, wrap your root component with <StrictMode> when you render it:

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';

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

我们建议在严格模式下封装你的整个应用,尤其是对于新创建的应用。如果你使用为你调用 createRoot 的框架,请查看其文档以了解如何启用严格模式。

¥We recommend wrapping your entire app in Strict Mode, especially for newly created apps. If you use a framework that calls createRoot for you, check its documentation for how to enable Strict Mode.

尽管严格模式检查仅在开发中运行,但它们可以帮助你发现代码中已存在的错误,但在生产中可靠地重现可能会很棘手。严格模式可让你在用户报告之前修复错误。

¥Although the Strict Mode checks only run in development, they help you find bugs that already exist in your code but can be tricky to reliably reproduce in production. Strict Mode lets you fix bugs before your users report them.

注意

严格模式在开发中启用以下检查:

¥Strict Mode enables the following checks in development:

所有这些检查仅用于开发,不会影响生产构建。

¥All of these checks are development-only and do not impact the production build.


为应用的一部分启用严格模式

¥Enabling Strict Mode for a part of the app

你还可以为应用的任何部分启用严格模式:

¥You can also enable Strict Mode for any part of your application:

import { StrictMode } from 'react';

function App() {
return (
<>
<Header />
<StrictMode>
<main>
<Sidebar />
<Content />
</main>
</StrictMode>
<Footer />
</>
);
}

在此示例中,不会针对 HeaderFooter 组件运行严格模式检查。但是,它们将在 SidebarContent 以及其中的所有组件上运行,无论深度如何。

¥In this example, Strict Mode checks will not run against the Header and Footer components. However, they will run on Sidebar and Content, as well as all of the components inside them, no matter how deep.


修复开发中双渲染发现的 bug

¥Fixing bugs found by double rendering in development

React 假定你编写的每个组件都是纯函数。 这意味着你编写的 React 组件必须始终在给定相同输入(props、状态和上下文)的情况下返回相同的 JSX。

¥React assumes that every component you write is a pure function. This means that React components you write must always return the same JSX given the same inputs (props, state, and context).

违反此规则的组件行为不可预测并导致错误。为了帮助你意外发现不纯的代码,严格模式会在开发过程中调用某些函数(仅那些应该是纯的函数)两次。这包括:

¥Components breaking this rule behave unpredictably and cause bugs. To help you find accidentally impure code, Strict Mode calls some of your functions (only the ones that should be pure) twice in development. This includes:

如果一个函数是纯函数,运行它两次不会改变它的行为,因为纯函数每次都会产生相同的结果。但是,如果一个函数是不纯的(例如,它会改变它接收到的数据),那么运行它两次往往会很明显(这就是它不纯的原因!)这有助于你及早发现并修复错误。

¥If a function is pure, running it twice does not change its behavior because a pure function produces the same result every time. However, if a function is impure (for example, it mutates the data it receives), running it twice tends to be noticeable (that’s what makes it impure!) This helps you spot and fix the bug early.

这里有一个例子来说明严格模式下的双重渲染如何帮助你及早发现错误。

¥Here is an example to illustrate how double rendering in Strict Mode helps you find bugs early.

这个 StoryTray 组件采用 stories 的数组,并在末尾添加最后一个 “创建故事” 项:

¥This StoryTray component takes an array of stories and adds one last “Create Story” item at the end:

export default function StoryTray({ stories }) {
  const items = stories;
  items.push({ id: 'create', label: 'Create Story' });
  return (
    <ul>
      {items.map(story => (
        <li key={story.id}>
          {story.label}
        </li>
      ))}
    </ul>
  );
}

上面的代码有错误。但是,很容易遗漏,因为初始输出看起来是正确的。

¥There is a mistake in the code above. However, it is easy to miss because the initial output appears correct.

如果 StoryTray 组件重新渲染多次,这个错误会变得更加明显。例如,当你将鼠标悬停在 StoryTray 上时,让我们用不同的背景颜色重新渲染它:

¥This mistake will become more noticeable if the StoryTray component re-renders multiple times. For example, let’s make the StoryTray re-render with a different background color whenever you hover over it:

import { useState } from 'react';

export default function StoryTray({ stories }) {
  const [isHover, setIsHover] = useState(false);
  const items = stories;
  items.push({ id: 'create', label: 'Create Story' });
  return (
    <ul
      onPointerEnter={() => setIsHover(true)}
      onPointerLeave={() => setIsHover(false)}
      style={{
        backgroundColor: isHover ? '#ddd' : '#fff'
      }}
    >
      {items.map(story => (
        <li key={story.id}>
          {story.label}
        </li>
      ))}
    </ul>
  );
}

请注意,每次将鼠标悬停在 StoryTray 组件上时,“创建故事” 都会再次添加到列表中。代码的目的是在末尾添加一次。但是 StoryTray 直接修改了属性中的 stories 数组。每次 StoryTray 渲染时,它都会在同一个数组的末尾再次添加 “创建故事”。换句话说,StoryTray 不是一个纯函数 - 多次运行它会产生不同的结果。

¥Notice how every time you hover over the StoryTray component, “Create Story” gets added to the list again. The intention of the code was to add it once at the end. But StoryTray directly modifies the stories array from the props. Every time StoryTray renders, it adds “Create Story” again at the end of the same array. In other words, StoryTray is not a pure function—running it multiple times produces different results.

要解决此问题,你可以制作数组的副本,然后修改该副本而不是原始副本:

¥To fix this problem, you can make a copy of the array, and modify that copy instead of the original one:

export default function StoryTray({ stories }) {
const items = stories.slice(); // Clone the array
// ✅ Good: Pushing into a new array
items.push({ id: 'create', label: 'Create Story' });

这将 使 StoryTray 功能纯粹。 每次调用时,它只会修改数组的一个新副本,而不会影响任何外部对象或变量。这解决了这个错误,但是在它的行为出现明显错误之前,你必须更频繁地重新渲染组件。

¥This would make the StoryTray function pure. Each time it is called, it would only modify a new copy of the array, and would not affect any external objects or variables. This solves the bug, but you had to make the component re-render more often before it became obvious that something is wrong with its behavior.

在最初的示例中,该错误并不明显。现在让我们将原始(有缺陷的)代码封装在 <StrictMode> 中:

¥In the original example, the bug wasn’t obvious. Now let’s wrap the original (buggy) code in <StrictMode>:

export default function StoryTray({ stories }) {
  const items = stories;
  items.push({ id: 'create', label: 'Create Story' });
  return (
    <ul>
      {items.map(story => (
        <li key={story.id}>
          {story.label}
        </li>
      ))}
    </ul>
  );
}

严格模式总是调用渲染函数两次,因此你可以立即看到错误(“创建故事” 出现两次)。这可以让你在流程的早期注意到此类错误。当你修复你的组件以在严格模式下渲染时,你还修复了许多未来可能的生产错误,例如之前的悬停功能:

¥Strict Mode always calls your rendering function twice, so you can see the mistake right away (“Create Story” appears twice). This lets you notice such mistakes early in the process. When you fix your component to render in Strict Mode, you also fix many possible future production bugs like the hover functionality from before:

import { useState } from 'react';

export default function StoryTray({ stories }) {
  const [isHover, setIsHover] = useState(false);
  const items = stories.slice(); // Clone the array
  items.push({ id: 'create', label: 'Create Story' });
  return (
    <ul
      onPointerEnter={() => setIsHover(true)}
      onPointerLeave={() => setIsHover(false)}
      style={{
        backgroundColor: isHover ? '#ddd' : '#fff'
      }}
    >
      {items.map(story => (
        <li key={story.id}>
          {story.label}
        </li>
      ))}
    </ul>
  );
}

如果没有严格模式,很容易遗漏错误,直到你添加更多重新渲染。严格模式使同样的错误立即出现。严格模式可帮助你在将错误推送给你的团队和用户之前找到它们。

¥Without Strict Mode, it was easy to miss the bug until you added more re-renders. Strict Mode made the same bug appear right away. Strict Mode helps you find bugs before you push them to your team and to your users.

阅读有关保持组件纯粹的更多信息。

¥Read more about keeping components pure.

注意

如果你挂载了 React 开发工具,则在第二次渲染调用期间的任何 console.log 调用都会稍微变暗。React DevTools 还提供了一个设置(默认关闭)来完全抑制它们。

¥If you have React DevTools installed, any console.log calls during the second render call will appear slightly dimmed. React DevTools also offers a setting (off by default) to suppress them completely.


修复通过在开发中重新运行副作用发现的错误

¥Fixing bugs found by re-running Effects in development

严格模式还可以帮助查找 副作用。 中的错误

¥Strict Mode can also help find bugs in Effects.

每个副作用都有一些设置代码,并且可能有一些清理代码。通常,React 在组件挂载(添加到屏幕)时调用设置,并在组件卸载(从屏幕移除)时调用清理。如果自上次渲染以来其依赖发生变化,React 会再次调用清理和设置。

¥Every Effect has some setup code and may have some cleanup code. Normally, React calls setup when the component mounts (is added to the screen) and calls cleanup when the component unmounts (is removed from the screen). React then calls cleanup and setup again if its dependencies changed since the last render.

当严格模式开启时,React 还将在开发过程中为每个副作用运行一个额外的设置+清理周期。这可能让人感到惊讶,但它有助于揭示难以手动捕获的微妙错误。

¥When Strict Mode is on, React will also run one extra setup+cleanup cycle in development for every Effect. This may feel surprising, but it helps reveal subtle bugs that are hard to catch manually.

下面是一个示例,用于说明在严格模式下重新运行副作用如何帮助你及早发现错误。

¥Here is an example to illustrate how re-running Effects in Strict Mode helps you find bugs early.

考虑这个将组件连接到聊天的示例:

¥Consider this example that connects a component to a chat:

import { createRoot } from 'react-dom/client';
import './styles.css';

import App from './App';

const root = createRoot(document.getElementById("root"));
root.render(<App />);

此代码存在问题,但可能不会立即清楚。

¥There is an issue with this code, but it might not be immediately clear.

为了使问题更明显,让我们实现一个功能。在下面的示例中,roomId 不是硬编码的。而是,用户可以从下拉列表中选择它们想要连接的 roomId。点击 “打开聊天”,然后一一选择不同的聊天室。跟踪控制台中的活动连接数:

¥To make the issue more obvious, let’s implement a feature. In the example below, roomId is not hardcoded. Instead, the user can select the roomId that they want to connect to from a dropdown. Click “Open chat” and then select different chat rooms one by one. Keep track of the number of active connections in the console:

import { createRoot } from 'react-dom/client';
import './styles.css';

import App from './App';

const root = createRoot(document.getElementById("root"));
root.render(<App />);

你会注意到打开的连接数始终在增长。在真实的应用中,这会导致性能和网络问题。问题是 你的副作用缺少清理函数:

¥You’ll notice that the number of open connections always keeps growing. In a real app, this would cause performance and network problems. The issue is that your Effect is missing a cleanup function:

useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]);

现在,你的副作用 “清理” 自行破坏了过时的连接,泄漏就解决了。但是,请注意,在你添加更多功能(选择框)之前,问题不会变得可见。

¥Now that your Effect “cleans up” after itself and destroys the outdated connections, the leak is solved. However, notice that the problem did not become visible until you’ve added more features (the select box).

在最初的示例中,该错误并不明显。现在让我们将原始(有缺陷的)代码封装在 <StrictMode> 中:

¥In the original example, the bug wasn’t obvious. Now let’s wrap the original (buggy) code in <StrictMode>:

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './styles.css';

import App from './App';

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

使用严格模式,你会立即发现存在问题(活动连接数跃升至 2)。严格模式为每个副作用运行额外的设置+清理周期。此副作用没有清理逻辑,因此它会创建一个额外的连接但不会破坏它。这暗示你缺少清理函数。

¥With Strict Mode, you immediately see that there is a problem (the number of active connections jumps to 2). Strict Mode runs an extra setup+cleanup cycle for every Effect. This Effect has no cleanup logic, so it creates an extra connection but doesn’t destroy it. This is a hint that you’re missing a cleanup function.

严格模式可让你在流程的早期发现此类错误。当你通过在严格模式下添加清理函数来修复你的副作用时,你还修复了许多未来可能的生产错误,例如之前的选择框:

¥Strict Mode lets you notice such mistakes early in the process. When you fix your Effect by adding a cleanup function in Strict Mode, you also fix many possible future production bugs like the select box from before:

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './styles.css';

import App from './App';

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

请注意控制台中的活动连接数如何不再继续增长。

¥Notice how the active connection count in the console doesn’t keep growing anymore.

如果没有严格模式,很容易遗漏需要清理的副作用。通过运行设置 → 清理 → 设置而不是为开发中的副作用设置,严格模式使缺失的清理逻辑更加明显。

¥Without Strict Mode, it was easy to miss that your Effect needed cleanup. By running setup → cleanup → setup instead of setup for your Effect in development, Strict Mode made the missing cleanup logic more noticeable.

阅读有关实现副作用清理的更多信息。

¥Read more about implementing Effect cleanup.


修复由严格模式启用的弃用警告

¥Fixing deprecation warnings enabled by Strict Mode

如果 <StrictMode> 树中任何地方的某些组件使用这些已弃用的 API 之一,React 会发出警告:

¥React warns if some component anywhere inside a <StrictMode> tree uses one of these deprecated APIs:

这些 API 主要用于较旧的 类组件,因此它们很少出现在现代应用中。

¥These APIs are primarily used in older class components so they rarely appear in modern apps.


React 中文网 - 粤ICP备13048890号