在React中,setstate是异步和同步。
setstate异步更新
当组件中的状态在开发过程中发生变化时,页面不会重新渲染。我们必须通过setstate告诉react数据已经改变并重新渲染页面。
先来看下面的例子:
constructor() { super(); this.state = { message: "Hello World", }; } changeText() { this.setState({ message: "Hello React", }); console.log(this.state.message); // Hello World }
最终打印的结果是Hello World;
由此可见,setstate是一种异步操作,我们在执行setstate后不能立即得到最新的state结果
那为什么setstate设计为异步呢?
setstate设计为异步,可显著提高性能
-
如果每次调用setstate进行更新,则意味着render函数会频繁调用,界面会重新渲染,效率很低;
-
最好的办法是获得多个更新,然后批量处理;
若state同步更新,但render函数尚未执行,则state和props无法保持同步;
state和props不能保持一致性,在开发中会出现很多问题;(例如,在嵌套组件时会影响子组件的状态)
如何获得异步的结果
setstate的回调
setstate接受两个参数:第二个参数是一个回调函数,它将在更新后执行。
changeText() { this.setState({ message: "Hello React", },()=>{ console.log('-----',this.state.message); // Hello React }); }
setstate一定是异步吗?
React18版之前
实际上可分为两种情况:
-
setstate在组件生命周期或React合成事件中是异步的;
-
在settimeout或原生DOM事件中,setstate同步
验证一:settimeout中的更新:
setTimeout(() => { this.setState({ message: "Hello React", }); console.log(this.state.message); // Hello React }, 0);
验证二:原生DOM事件:
componentDidMount() { const btnEl = document.querySelector("#btn"); btnEl.addEventListener("click", () => { this.setState({ message: "Hello React", }); console.log(this.state.message); // Hello React }); }
React18版之后
Setstate默认为异步
-
React18后,默认所有操作都放入批处理(异步处理)
要想同步获得代码,需要执行特殊的flushSync操作:
import { flushSync } from "react-dom"; changeText() { flushSync(() => { this.setState({ message: "Hello React", }); }); console.log(this.state.message); // Hello React }