我将分两步介绍我的问题,两者的代码块略有不同。
步骤1:
下面我们有一个 React 应用程序,它每两秒渲染一次,因此导致浏览器将渲染打印到控制台。如果用户按下任意键,渲染将停止,从而停止控制台打印。请暂时忽略注释掉的行。
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 步导致额外渲染的原因可能是什么。也许这很明显?
如果我注释掉由 setInterval 运行的其他状态更改,则setIsPaused(isPaused)永远不会导致新的渲染,这让我更加困惑。