前言我自己的想法(2021)8月份面试的时候,被面试官问了几个setState的问题。现在想来,虽然回答了上面的问题,但是理解的并不深刻。我知道setState是为了性能而设计成“异步”的,但是当涉及到源代码解释时,我很茫然;我知道如何让它同步,但是当涉及到真正的代码情况时,我不知道如何下手。毕竟我是准备把这些概念当面写下来的,并没有真正理解。在了解setState之前,我们问了几个常见的问题。setState是同步的还是异步的?如果是异步的,如何让它同步呢?为什么要这样设计?使用React的一个基本概念和概念是UI=f(data)。修改数据带动UI变化,那么怎么修改呢?React提供了一个API——setState(类组件的修改方法)官网介绍:setState()将组件状态的更新加入队列,并通知React组件及其子组件需要用更新后的状态重新渲染。这是更新UI以响应事件处理程序和处理服务器数据的主要方式。为了获得更好的感知性能,React延迟调用它,然后一次性更新多个组件。React不保证状态更改会立即生效setState()并不总是立即更新组件。它分批推迟更新。这使得在调用setState()之后立即读取this.state成为一种危险。为了消除隐患,请使用componentDidUpdate或者setState的回调函数(setState(updater,callback)),两者都可以保证应用更新后触发,除非shouldComponentUpdate()返回false,否则setState()会一直执行重新-渲染操作。如果使用了可变对象,并且在shouldComponentUpdate()中无法实现条件渲染,那么只在新旧状态不一致时才调用setState()可以避免不必要的重新渲染使用方法setState(updater,[callback])参数一是带形式参数的更新函数:(state,props)=>stateChange//例如//this.setState((state,props)=>{//return{counter:state.counter+props.step};//});setState的第一个参数除了可以接受函数,还可以接受对象类型:setState(stateChange[,callback])//例如:this.setState({count:2})setState的第二个参数是可选的回调函数将在setState完成合并并重新渲染组件后执行。通常,我们推荐使用componentDidUpdate而不是这个方法setState(stateChange[,callback])//例如:this.setState({count:2},()=>{console.log(this.state.count)})使用componentDidUpdate相对于setState回调有什么优势?stackoverflow上有人问过,也有人回答过:setState什么时候才能更好的实现一致的逻辑批量更新?当外部代码需要等待状态更新时,比如PromisesetState的特性——批处理如果在同一个周期处理多个setState,比如同一个周期设置多次商品数据,则相当于:this.setState({count:state.count+1});this.setState({count:state.count+1});this.setState({count:state.count+1});//===Object.assign(count,{quantity:state.quantity+1},{quantity:state.quantity+1},...)后调用的setState会覆盖同一个循环中先调用的setState的值setState(stateChange[,callback])setState((state,props)=>stateChange[,callback])setState一定会触发update过程,但不一定会导致render被执行,因为shouldCompomentUpdate可以返回false批处理导致的问题问题一:为什么使用setStatecontinuously=0时不能实时更改state.count;this.setState({count:state.count+1});this.setState({count:state.count+1});this.setState({count:state.count+1});//state.count===1,因为this.setState而不是3该方法是批处理的,后面调用的setState会在同一个周期覆盖先调用的setState的值,如下图:state.count=0;this.setState({count:state.count+2});这个.setState({count:state.count+3});this.setState({count:state.count+4});//state.count===4问题2:为什么setState而不是this。state.xx=哦?因为setState所做的不仅仅是修改this.state的值,最重要的是它会触发React的更新机制,会进行diff,然后将patch部分更新到真正的dom中。如果你直接this.state.xx=oo的话,state的值确实会改变,但是不会驱动React重新渲染。setState可以帮助我们更新视图,触发shouldComponentUpdate、render等一系列函数调用。对于批处理,React会将setState的效果放入队列中,在事件结束后生成重新渲染,以尽量减少VirtualDOM和DOM树操作,提高性能。调用setState后,ReactPeriodic函数的生命周期会依次执行staticgetDerivedStateFromPropsshouldComponentUpdaterendergetSnapshotBeforeUpdatecomponentDidUpdate。问题三:那为什么会出现异步呢?(为什么要这样设计?)因为性能优化。如果每次设置setState都需要更新数据,那么更新过程会经历5个生命周期。一轮生命周期结束后,需要花费大量的时间来比较render函数的结果和更新真实的DOM。因此,将每次调用放在一起一次性处理,可以减少对DOM的操作,提高应用性能。问题四:如何在异步函数中准确获取更新后的状态?通过第二个参数中的回调获取更新结果setState(partialState,callback)onHandleClick(){this.setState({count:this.state.count+1,},()=>{console.log("Callbackafterclick",this.state.count);//最新值});}或者你可以直接给state传一个函数来显示同步情况this.setState(state=>{console.log("functionmode",state.count);返回{count:state.count+1};});执行原理首先了解三种渲染模式:legacy模式:ReactDOM.render(
