【问题标题】:React renders without actually changing the state when setInterval is used使用 setInterval 时,React 渲染而不实际更改状态
【发布时间】:2021-01-12 17:53:14
【问题描述】:

我将分两步介绍我的问题,其中的代码块略有不同。

第 1 步:

下面我们有一个 React 应用程序,它每两秒渲染一次,因此导致浏览器打印 render 到控制台。如果用户按下任何键,渲染将停止,进而停止控制台打印。请暂时忽略注释掉的行。

import { useState, useEffect, useRef } from 'react';

function App() {

  const [number, setUpdate] = useState(0);
  const [isPaused, setIsPaused] = useState(false);

  const intervalRef = useRef(undefined);

  useEffect(() => {
    intervalRef.current = setInterval(() => setUpdate(prevNumber => ++prevNumber), 2000);
    window.addEventListener('keydown', handleKeyDown);
  }, []);

  const handleKeyDown = () => {
    clearInterval(intervalRef.current);
    console.log('console log here');

    // setIsPaused(isPaused);
  };

  console.log('render');

  return null;
};

export default App;

这是应用程序的屏幕截图:

上面发生的事情是,我让组件渲染了五次,然后我按下了一个键来停止组件的渲染。

第 2 步:

在第 2 步中,除了没有注释掉handleKeyDown 中设置的状态之外,我们拥有完全相同的应用程序。

  const handleKeyDown = () => {
    clearInterval(intervalRef.current);
    console.log('console log here');

    // This is no longer commented out. Why does it cause a new render?
    setIsPaused(isPaused);
  };

这是应用程序的屏幕截图,其中包含在步骤 2 中进行的代码更改:

再次,我让组件在我按下一个键后呈现五次。但是现在有一个额外的渲染,即使状态不应该改变(因为状态实际上并没有发生变化,因为我们设置了与状态中已经存在的值相同的值)setIsPaused(isPaused)

我很难理解在第 2 步导致额外渲染的原因可能是什么。也许这很明显?

setIsPaused(isPaused) 如果我注释掉由 setInterval 运行的其他状态更改,则永远不会导致新的渲染,这让我更加困惑。

【问题讨论】:

    标签: reactjs render setinterval use-state react-state


    【解决方案1】:

    更新的状态从未手段DOM将重新呈现,̶你是对̶̶s̶e̶t̶I̶s̶P̶a̶u̶s̶e̶d̶(̶i̶s̶P̶a̶u̶s̶e̶d̶)̶̶不会重新呈现DOM中,̶但将设置状态,并给你更新̶v̶a̶l̶u̶e̶.̶̶(我正在考虑唯一的状态̶w̶i̶t̶h̶̶f̶i̶e̶l̶d̶̶̶i̶s̶P̶a̶u̶s̶e̶d̶̶̶n̶o̶t̶h̶i̶n̶g̶̶e̶l̶s̶e̶)̶

    更新:在阅读接受的答案之前,我确实知道这种行为存在。

    【讨论】:

      【解决方案2】:

      这是一个已知的怪癖,请参阅#17474。这是新并发模式引入的副作用。组件函数确实重新运行,但 DOM 将保持未被篡改。

      我还发现有人发帖this interesting example。您可以使用代码尝试 exp。组件函数包含类似<div>{Math.random()}</div> 之类的内容,尽管在该函数的额外重新运行中随机数确实发生了变化,但如果状态不改变,它不会反映到 DOM 上。

      结论。大多数情况下,您可以认为这种副作用是无害的。

      【讨论】:

        猜你喜欢
        • 2018-11-29
        • 2020-10-03
        • 1970-01-01
        • 2021-11-24
        • 2019-02-27
        • 2020-04-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多