【问题标题】:Why does React call my component more times than needed?为什么 React 调用我的组件的次数比需要的多?
【发布时间】:2021-08-05 11:51:11
【问题描述】:

我有一个简单的组件示例,它使用useRef() 来计算我的组件已呈现的次数,并使用useState() 来维持某种状态:

const {useState, useRef} = React;
const App = () => {
  const [counter, setCounter] = useState(0);
  const renderCount = useRef(0);
  const onClick = () => {
    setCounter(1);
  }
  renderCount.current++;
  alert("rendering"); // executes 3 times, not twice.
  return <div>
    <p>Render count: {renderCount.current}</p>
    <button onClick={onClick}>{counter}</button>
  </div>
}

ReactDOM.render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>

当我运行上面的 sn-p 时,alert 触发并且 ref 计数器由于第一次渲染而增加。当我第一次单击该按钮时,会调用setCounter(1),这会导致组件重新渲染/重新执行(如预期的那样),从而导致警报第二次出现并且引用计数器增加。当我第二次单击该按钮时,setCounter(1) 运行(它不会更新状态,因为它已经是 1)。由于状态没有改变,我希望不需要重新渲染,因此我的 App 组件不会再次执行。但是,我反而看到了第三个警报,表明该组件再次执行,但是 ref 计数器没有增加,第二次单击后呈现的输出也没有改变。进一步单击该按钮不会按预期显示任何警报。我的问题是,当状态没有改变时(即:第二次点击按钮),为什么 React 会再次执行我的 App 组件?

【问题讨论】:

    标签: javascript reactjs setstate


    【解决方案1】:

    这是 React 重新渲染的渲染行为,这是一种特殊情况。如果你将 state 更新为与当前 state 相同的值,那么 React 会再次重新渲染组件并避免后续的重新渲染。

    • 第一次渲染是初始渲染,状态是0
    • 第二次渲染是为了状态变化state是1
    • 第三次渲染是针对特殊情况(这不是初始渲染)state是1

    但是,这种不必要的重新渲染不适用于初始渲染。我的意思是,如果您在onClick 方法中使用setCounter(0) 而不是setCounter(1),那么即使随后调用onClick 方法,组件也只会呈现一次。

    流程如下图:

    原因是; React 无法猜测渲染的输出不会改变,它必须再渲染一次,并将结果与​​之前的渲染进行比较。但我不确定它在初始状态下是如何处理的(可能是一个标志)。文档中没有太多关于它的信息。

    您可能认为存在效率问题,但实际上没有。 React 渲染周期有两个阶段:渲染阶段提交阶段。 DOM 在提交阶段后更新,在这种情况下,进程不会进入提交阶段,并且将引导 DOM 更新

    【讨论】:

      【解决方案2】:

      您没有使用 React 的钩子 useEffect(),这就是为什么您的函数(随时调用)将其称为本地作用域函数。把你的函数组件想象成一个字母。您将其传递给已关闭并签名的letterman。但是在您的情况下,您将它打开(在传输期间它被读取和调用)但已签名(它知道它将在哪里),因此您需要使用钩子/生命周期方法来控制您的 React 组件。

      这就是您遇到警报和增量的原因。

      如果您已经使用过 React 类组件,那么您应该知道它的生命周期是什么。如果没有,我建议您阅读这篇文章:React Lifecycles

      useEffect 具有componentDidMountcomponentDidUpdatecomponentWillUnmount 之间的连接行为。每当您更新状态或道具时,都会调用此方法并执行给定的代码。

      【讨论】:

      • 感谢 Maciej 的回答,但我不确定这是否能回答我的问题。我的问题是 为什么 当状态没有改变时,App 组件函数会额外执行 alert() / 执行?我知道我可以使用 useEffect 来控制何时执行警报(警报只是在那里显示应用程序正在第三次重新执行)。
      • 您正在调用组件范围内的函数,组件没有重新渲染,但它调用了一个函数和它本身。重新渲染 React 意味着更新文档的树,所以会调用函数,但这并不一定意味着 React 会使用返回的值来更新文档的树。
      猜你喜欢
      • 1970-01-01
      • 2021-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-08
      • 1970-01-01
      • 2015-04-03
      • 1970-01-01
      相关资源
      最近更新 更多