javascript - React hooks:为什么异步函数中的多个 useState 设置器会导致多次重新渲染?
问题描述
以下 onClick 回调函数将导致 1 次重新渲染:
const handleClickSync = () => {
// Order of setters doesn't matter - React lumps all state changes together
// The result is one single re-rendering
setValue("two");
setIsCondition(true);
setNumber(2);
};
React 将所有三种状态更改集中在一起并导致 1 次重新渲染。
然而,下面的 onClick 回调函数会导致 3 次重新渲染:
const handleClickAsync = () => {
setTimeout(() => {
// Inside of an async function (here: setTimeout) the order of setter functions matters.
setValue("two");
setIsCondition(true);
setNumber(2);
});
};
useState
这是每个二传手的重新渲染。此外,设置器的顺序会影响每个渲染中的值。
问题:为什么我使函数异步(此处通过setTimeout
)这一事实会导致状态更改一个接一个地发生,从而导致 3 次重新渲染。如果函数是同步的,只导致一次重新渲染,为什么 React 会将这些状态更改集中在一起?
您可以使用此 CodeSandBox来体验该行为。
解决方案
如果代码执行在 react 内部开始(例如,一个onClick
监听器或 a useEffect
),那么 react 可以确保在您完成所有状态设置后,执行将返回到 react 并且可以从那里继续。所以对于这些情况,它可以让代码继续执行,等待返回,然后同步进行一次渲染。
但是,如果代码执行是随机开始的(例如,在 a 中setTimeout
,或者通过解析一个 promise),那么当你完成时代码不会返回响应。所以从 react 的角度来看,它正在安静地睡觉,然后你调用setState
,迫使 react 像“啊!他们正在设置状态!我最好渲染”。有一些异步方式可以让 react 等待看你是否在做更多事情(例如,超时 0 或微任务),但没有同步方式让 react 知道你什么时候完成。
在当前版本的 react 中,您可以使用以下命令告诉 react 批处理多个更改unstable_batchedUpdates
:
import { unstable_batchedUpdates } from "react-dom";
const handleClickAsync = () => {
setTimeout(() => {
unstable_batchedUpdates(() => {
setValue("two");
setIsCondition(true);
setNumber(2);
});
});
};
一旦 react 18 到来,这将不是必需的,因为他们对并发模式渲染所做的更改将消除对此的需要。
推荐阅读
- kotlin - 非直观类型推断的 Kotlin 案例
- fortran - 即使重新加载库,JNA 也会保持状态
- python-3.x - 是否可以根据 PostgreSQL 中的输入列生成列
- perl - 如何在现代 perl 中使用伪散列?
- jquery - 试图突出显示活动菜单项
- javascript - 使用 JavaScript,如何使用 .toExponential() 函数,但只使用两位小数(9.99e9,而不是 9.9999e9)
- python - 以 JSON/字典格式输出 API 请求
- php - 如何将密钥添加到 php 数组作为动态编程
- java - 绘制方法重复 3 次而不是 1 次
- forms - 如何用andt形式取消焦点()