React useState 导致双重渲染

IT技术 reactjs react-hooks
2021-04-05 01:01:10

考虑规范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;

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

短屏幕

3个回答

把它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;

编辑精彩特斯拉-cf8uu

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

在此处输入图片说明

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

使用效果

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

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

react严格模式

检测意外的副作用

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

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

这仅适用于开发模式。

是的。并且只是为了一些快速的脏日志(比如调试或其他东西),在函数体中放置日志并不会真正造成任何伤害。
2021-06-04 01:01:10
谢谢。根据该图,在组件主体内进行日志记录是没有意义的,因为 React 可以随时重新启动“渲染阶段”,而useEffect确保在“提交阶段”(实际 DOM 渲染)调用并且所有日志记录都应该在那里完成。我这样说是否正确?
2021-06-06 01:01:10

关于双重重新渲染的更多信息(根据封闭的react问题)。

这是 StrictMode 的一个有意特性。这仅发生在开发中,并有助于发现进入渲染阶段的意外副作用。我们只对带有 Hook 的组件执行此操作,因为它们更有可能在错误的地方意外产生副作用。

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

另一个相关问题在这里。

useState() 做双重渲染

const countRef = useRef(1);
countRef.current += 1;

这种方式渲染将一次执行 2 次


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

这种方式渲染将一次执行 1 次