【问题标题】:React useState cause double renderingReact useState 导致双重渲染
【发布时间】:2020-04-06 05:25:16
【问题描述】:

考虑典型的useState 示例:

import React, { useState } from 'react';

const MyComponent = () => {
  const [count, setCount] = useState(0);
  console.log(count);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
      count: {count}
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

export default MyComponent;

单击按钮会使每个状态打印两次。这是为什么呢?

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    console.log 放入没有依赖关系的useEffect 挂钩中,您会发现它实际上 不会渲染两次。

    import React, { useEffect, useState } from 'react';
    
    const MyComponent = () => {
      const [count, setCount] = useState(0);
    
      useEffect(() => {
        console.log(count);
      });
      
      return (
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
          count: {count}
          <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
      );
    };
    
    export default MyComponent;
    

    这是一个很好的组件生命周期图,它列出了基于类的生命周期函数,但渲染/提交阶段是相同的。

    需要注意的重要一点是组件可以“渲染”而无需实际提交(即您在屏幕上看到的常规渲染)。单独的 console.log 就是其中的一部分。效果在“提交”阶段之后运行。

    useEffect

    ... 传递给 useEffect 的函数将运行 在渲染提交到屏幕之后。 ...

    默认情况下,效果会在每次完成渲染后运行,...

    反应严格模式

    Detecting Unexpected Side-effects

    严格模式无法自动为您检测副作用,但它 可以通过使它们更具确定性来帮助您发现它们。 这是通过有意双重调用以下函数来完成的:

    • 类组件constructorrendershouldComponentUpdate方法
    • 类组件静态getDerivedStateFromProps方法
    • 函数组件体
    • 状态更新函数(setState 的第一个参数)
    • 函数传递给useStateuseMemouseReducer

    这仅适用于开发模式。

    【讨论】:

    • 谢谢。根据该图,组件主体内的日志记录是没有意义的,因为 React 可以随时重新启动“渲染阶段”,而确保在“提交阶段”(实际 DOM 渲染)调用useEffect,并且所有日志记录都应该是在那里完成。我这样说对吗?
    • 是的。并且只是为了一些快速的脏日志(比如调试或其他东西)在函数体中删除日志并不会造成任何伤害。
    【解决方案2】:

    有关双重重新渲染的更多信息(根据已关闭的反应问题)。

    这是 StrictMode 的一个有意的功能。这只发生在开发中,有助于发现渲染阶段的意外副作用。我们只对带有 Hook 的组件执行此操作,因为这些组件更有可能意外地在错误的位置产生副作用。

    https://github.com/facebook/react/issues/15074

    另一个相关问题在这里。

    useState() do double render

    【讨论】:

      【解决方案3】:
      const countRef = useRef(1);
      countRef.current += 1;
      

      这样渲染一次会执行2次


      const countRef = useRef(1);
      useEffect(() => {
         countRef.current += 1;
      })
      

      这样渲染一次会执行1次

      【讨论】:

        猜你喜欢
        • 2020-07-18
        • 1970-01-01
        • 1970-01-01
        • 2019-07-22
        • 1970-01-01
        • 2020-08-15
        • 1970-01-01
        • 2022-06-18
        相关资源
        最近更新 更多