React的setState执行机制
1. setState基本特点 1. setState是同步执行的 setState是同步执行的,但是state并不一定会同步更新 2. setState在React生命周期和合成事件中批量覆盖执行 在React的生命周期钩子和合成事件中,多次执行setState,会批量执行 具体表现为,多次同步执行的setState只有最后一次起作用,前面的全被覆盖 当遇到多个setState调用时候,会提取单次传递setState的对象,把他们合并在一起形成一个新的 const a = {name : ‘kong‘,age : ‘17‘} const b = {name : ‘fang‘,sex : ‘men‘} Object.assign({},a,b); //{name : ‘fang‘,age : ‘17‘,sex : ‘men‘} name被后面的覆盖了,但是age和sex都起作用了 例如: class Hello extends React.Component { constructor(){ super(); this.state = { name: ‘aa‘ } } componentWillMount(){ this.setState({ name: ‘aa‘ + 1 }); console.log(this.state.name); //aa this.setState({ name: ‘aa‘ + 1 }); console.log(this.state.name); //aa } render() { return <div> <div>Hello {this.props.name}</div> <div>Hello {this.state.name}</div> </div>; } } ReactDOM.render( <Hello name="World" />,document.getElementById(‘container‘) ); componentWillMount中两个log均为初始状态aa,而render中的state.name则为aa2 3. setState在原生事件,setTimeout,setInterval,Promise等异步操作中,state会同步更新 异步操作中setState,即使在React的钩子或合成事件中,state都不会批量更新,而是会同步更新, 2. setState的形式 setState(object,[callback]) //对象式,object为nextState setState(function,[callback]) //函数式,function为(prevState,props) => stateChange [callback]则为state更新之后的回调,此时state已经完成更新,可以取到更新后的state 使用者两者形式的setState,state的更新都是异步的,但是多次连续使用函数式的setState, 如果对象式和函数式的setState混合使用,则对象式的会覆盖前面无论函数式还是对象式的任何setState, 例如: function increment(state,props){ return {count: state.count + 1}; } function incrementMultiple(){ this.setState(increment); this.setState(increment); this.setState({count: this.state.count + 1}); this.setState(increment); } 上面三个函数式的setState中间插入一个对象式的setState,则最后的结果是2,而不是4, 3. setState的基本过程 setState的调用会引起React的更新寿命周期的4个函数执行。 shouldComponentUpdate 当shouldComponentUpdate执行时,返回true,进行下一步,this.state没有被更新 当componentWillUpdate被调用时,this.state也没有被更新 直到render被调用时候,this.state才被更新。 总之,直到下一次render函数调用(或者下一次shouldComponentUpdate返回false时)才能得到更新后的this.state 1. setState函数式 2. setState在setTimeout,Promise等异步中执行 setStatePromise(updator) { return new Promise(((resolve,reject) => { this.setState(updator,resolve); })); } componentWillMount() { this.setStatePromise(({ num }) => ({ num: num + 1,})).then(() => { console.log(this.state.num); }); } 或者 function setStateAsync(nextState){ return new Promise(resolve => { this.setState(nextState,resolve); }); } async func() { ... await this.setStateAsync({count: this.state.count + 1}); await this.setStateAsync({count: this.state.count + 1}); } 3. setState callback setState({ index: 1 }},function(){ console.log(this.state.index); }) 4. componentDidUpdate componentDidUpdate(){ console.log(this.state.index); } 4. setState批量更新的过程 在React的生命周期和合成事件执行前后都有相应的钩子,分别是pre钩子和post钩子,pre钩子会调用batchedUpdate方法将isBatchingUpdates变量置为true,开启批量更新,而post钩子会将isBatchingUpdates置为false 如下图所示: isBatchingUpdates变量置为true,则会走批量更新分支,setState的更新会被存入队列中,待同步代码执行完后,再执行队列中的state更新。 而在原生事件和异步操作中,不会执行pre钩子,或者生命周期的中的异步操作之前执行了pre钩子,但是pos钩子也在异步操作之前执行完了,isBatchingUpdates必定为false,也就不会进行批量更新。 5. setState的缺点 1. setState有可能循环调用 调用setState之后,shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate 等生命周期函数会依次被调用(如果shouldComponentUpdate没有返回 false的话),如果我们在render、componentWillUpdate或componentDidUpdate中调用了setState方法,那么可能会造成循环调用,最终导致浏览器内存占满后崩溃 2、setState可能会引发不必要的渲染 可能造成不必要渲染的因素如下: 3、setState并不总能有效地管理组件中的所有状态 因为组件中的某些属性是和视图没有关系的,当组件变得复杂的时候可能会出现各种各样的状态需要管理,这时候用setState管理所有状态是不可取的。state中本应该只保存与渲染有关的状态,而与渲染无关的状态尽量不放在state中管理,可以直接保存为组件实例的属性,这样在属性改变的时候,不会触发渲染,避免浪费 6. setState和replaceState的区别 setState是修改其中的部分状态,相当于Object.assign,只是覆盖,不会减少原来的状态 7. 一个实例分析 上图的执行结果为 0 0 1 1 3 4 ? ? 参考: http://www.360doc.com/content/17/0803/18/27576111_676420051.shtml https://blog.csdn.net/kongjunchao159/article/details/72626637 https://blog.csdn.net/michellezhai/article/details/80098211 https://www.cnblogs.com/danceonbeat/p/6993674.html https://segmentfault.com/a/1190000010682761 https://segmentfault.com/a/1190000015821018 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |