vad*_*irn 28 reactjs react-hooks
对于类组件,this.setState如果在事件处理程序内部则调用批处理.但是如果在事件处理程序之外更新状态并使用'useState'钩子会发生什么?
function Component() {
const [a, setA] = useState('a');
const [b, setB] = useState('b');
function handleClick() {
Promise.resolve().then(() => {
setA('aa');
setB('bb');
});
}
return <button onClick={handleClick}>{a}-{b}</button>
}
Run Code Online (Sandbox Code Playgroud)
它会useState马上渲染吗?或者它会是aa - bb然后aa - b呢?
Pat*_*und 32
TL; DR - 如果状态更改是异步触发的(例如,包含在一个promise中),它们将不会被批处理; 如果它们被直接触发,它们将被批量处理.
我已经设置了一个沙箱来试试这个:https://codesandbox.io/s/402pn5l989
import React, { Fragment, useState } from 'react';
import ReactDOM from 'react-dom';
import './styles.css';
function Component() {
const [a, setA] = useState('a');
const [b, setB] = useState('b');
console.log('a', a);
console.log('b', b);
function handleClickWithPromise() {
Promise.resolve().then(() => {
setA('aa');
setB('bb');
});
}
function handleClickWithoutPromise() {
setA('aa');
setB('bb');
}
return (
<Fragment>
<button onClick={handleClickWithPromise}>
{a}-{b} with promise
</button>
<button onClick={handleClickWithoutPromise}>
{a}-{b} without promise
</button>
</Fragment>
);
}
function App() {
return <Component />;
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
Run Code Online (Sandbox Code Playgroud)
我创建了两个按钮,一个触发状态更改包含在代码示例中的promise中,另一个触发状态更改直接.
如果你看一下控制台,当你点击按钮"与承诺",它首先会显示a aa和b b,然后a aa和b bb.
所以答案是否定的,在这种情况下,它不会立即呈现aa - bb,每个状态更改触发一个新的渲染,没有批处理.
但是,当您点击按钮"不承诺",控制台将显示a aa和b bb马上.
因此,在这种情况下,React会对状态更改进行批处理,并为两者进行一次渲染.
Shu*_*tri 16
当前,在 React v16 及更早版本中,默认情况下仅对 React 事件处理程序(如click或onChange等)内的更新进行批处理。所以就像类状态更新在钩子中以类似的方式进行批处理一样
有一个不稳定的 API 可以在您需要时在极少数情况下强制在事件处理程序之外进行批处理。
ReactDOM.unstable_batchedUpdates(() => { ... })
Run Code Online (Sandbox Code Playgroud)
有计划在将来的版本中批处理所有状态更新,可能是 v17 或更高版本。
现在,如果事件处理程序中的状态更新调用在异步函数中或由于异步代码而触发,它们将不会被批处理,而直接更新将被批处理
在没有同步代码状态更新的情况下,批处理和异步代码更新不是
function App() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
// async update from useEffect
useEffect(() => {
setTimeout(() => {
setCount1(count => count + 1);
setCount2(count => count + 2);
}, 3000);
}, []);
const handleAsyncUpdate = async () => {
await Promise.resolve("state updated");
setCount1(count => count + 2);
setCount2(count => count + 1);
};
const handleSyncUpdate = () => {
setCount1(count => count + 2);
setCount2(count => count + 1);
};
console.log("render", count1, count2);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button type="button" onClick={handleAsyncUpdate}>
Click for async update
</button>
<button type="button" onClick={handleSyncUpdate}>
Click for sync update
</button>
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
https://codesandbox.io/s/739rqyyqmq
小智 6
@Patrick Hund 已经给出了答案。只是想在这里更新一下,使用 React 18 批处理状态更新可以用于 Promise,默认情况下 setTimeout 也可以。
在 React 18 之前,我们仅在 React 事件处理程序期间批量更新。默认情况下,React 中不会批处理 Promise、setTimeout、本机事件处理程序或任何其他事件内部的更新。
查看此内容以获取详细说明。https://github.com/reactwg/react-18/discussions/21
| 归档时间: |
|
| 查看次数: |
4663 次 |
| 最近记录: |