将状态设置为相同值后,React 组件重新渲染

Fil*_*zyk 6 rendering reactjs react-hooks react-state

import { useState } from "react";

export default function App() {
  const [buttonClicked, setButtonClicked] = useState(false);

  console.log('Render');

  return (
    <div className="App">
      <button onClick={() => setButtonClicked(true)}>Click me</button>
      {buttonClicked && <div>Button was clicked</div>}
    </div>
  );
}

Run Code Online (Sandbox Code Playgroud)

该组件未在StrictMode. 它首先渲染,因此我们在控制台中看到一个渲染。当我们单击按钮时,它会因状态更新而重新呈现。我们可以Render再次在控制台看到。但是,令我惊讶的是,当我们再次单击该按钮时,它也会重新渲染该组件,我们Render第三次在控制台中看到。

我认为状态更新正在检查值是否已更改,因此不会第三次渲染。

对我来说更奇怪的是,当我们第三次单击该按钮时,它不会重新渲染组件。

为什么会发生这种情况?

Codesandbox: https://codesandbox.io/s/proud-star-rg49x9? file=/src/App.js:0-336

Plu*_*uto 1

在您的代码中,没有第三次渲染。它是组件调用,而不是渲染。

例如:

import { useEffect, useState } from "react";

export default function App() {
  const [buttonClicked, setButtonClicked] = useState(false);
  console.log("invoked");

  useEffect(() => {
    console.log("render");
  });

  return (
    <div className="App">
      <button onClick={() => setButtonClicked(true)}>true</button>
      <button onClick={() => setButtonClicked(false)}>false</button>
      {buttonClicked && <div>Button was clicked</div>}
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

要测试此代码,请转到codesandbox

此代码在控制台中登录如下:

invoked // first mount
render  // first mount
invoked // first click true button (if you click false button, there is no effect)
render  // first click true button
invoked // second click true button, after then if you click true button, there is no logging.
invoked // first click false button
render  // first click false button
invoked // second click false button, after then if you click false button, there is no logging.
Run Code Online (Sandbox Code Playgroud)

return之外的语句console.log与渲染过程无关。它只是一条普通的 JavaScript 语句,每次调用该函数时都会运行。组件函数可以因各种原因被调用,例如 props 更改、上下文更改或父级重新渲染。

React 可以调用组件函数来检查输出中的更改,但它不会重新渲染组件或其子组件,除非输出存在差异。因此,console.logreturn 之外的语句将在每次调用组件函数时运行,但hookconsole.log内的语句useEffect只会在初始渲染之后和每次重新渲染之后运行。

如果状态值与之前相同,React 将退出重新渲染。

根据 React 文档:

如果将 State Hook 更新为与当前状态相同的值,React 将退出而不渲染子项或触发效果。

这意味着单击同一按钮两次后,React 将不会重新渲染组件或其子组件,因为输出没有变化。React 也不会再次调用组件函数,除非有理由检查输出中的更改,例如 props 更改、上下文更改或父级重新渲染。这就是 React 通过避免不必要的工作来优化应用程序性能的方式。


更新的答案

在我的示例中,如果您false第一次单击按钮,您将看不到更多日志。这是因为 React 在第一次挂载后就已经退出了。

你可以看到这个:

invoked // first mount
render  // first mount
Run Code Online (Sandbox Code Playgroud)