React setState 立即生效的几种方式?
首先了解一个造成不能立即生效的原因,setState异步的原因是因为react的监听事件为合成事件,state执行过程中会经历一个生命周期函数,执行多个setState会被合并,提升性能,下面几种方式可以避免我们的问题:
- shouleComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
setState合适同步何时异步?
由React控制的事件处理程序,以及生命周期函数调用setState不会同步更新state 。
React控制之外的事件中调用setState是同步更新的。比如原生js绑定的事件,setTimeout/setInterval等。
this.setState({ count: this.state.count + 1 }); this.setState({ count: this.state.count + 1 }); this.setState({ count: this.state.count + 1 }); // 执行后结果相当于 const count = this.state.count; this.setState({ count: count + 1 }); this.setState({ count: count + 1 }); this.setState({ count: count + 1 });
1、传递函数()=>{return state},react提供的参数props保证每次都拿到最新的
// 第一个函数调用更新state,第二个函数是更新完之后的回调。 this.setState((prevState, props) => { return { age: prevState.count + 1, };
// 获取state console.log(this.state); // 1
});
2、设置setTimeout、setInterval,和事件玄幻有关系
setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。
setTimeout(() => { this.setState(prevState => { return { age: prevState.count + 1, }; }); // 获取state console.log(this.state); // 1 }, 0);
3、设置js原生监听事件addEventListener
原生事件的调用栈就比较简单了,因为没有走合成事件的那一大堆,直接触发click事件,到
requestWork
,在requestWork
里由于 expirationTime === Sync
的原因,直接走了 performSyncWork
去更新,并不像合成事件或钩子函数中被return,所以当你在原生事件中setState后,能同步拿到更新后的state值。handleClick3 = () => { this.setState({ count: this.state.count + 1 }); // 某些条件可能获取不到最新的值 console.log(this.state); }; componentDidMount() { document.body.addEventListener('btn4', this.handleClick3, false); }
class Demo extends React.Component { state = { count: 0, }; handleClick0 = () => { this.setState({ count: this.state.count + 1 }); this.setState({ count: this.state.count + 1 }); this.setState({ count: this.state.count + 1 }); // 某些条件可能获取不到最新的值 console.log(this.state); }; // 1、把对象改为回调函数 handleClick1 = () => { this.setState(prevState => { return { age: prevState.count + 1, }; }); // 获取state console.log(this.state); // 1 }; // 2、设置setTimeout,setInterval handleClick2 = () => { setTimeout(() => { this.setState(prevState => { return { age: prevState.count + 1, }; }); // 获取state console.log(this.state); // 1 }, 0); }; // 3、设置原生监听事件,不同调用react的一些生命周期,直接触发onclick handleClick3 = () => { this.setState({ count: this.state.count + 1 }); // 某些条件可能获取不到最新的值 console.log(this.state); }; componentDidMount() { document.body.addEventListener('btn4', this.handleClick3, false); } render() { return ( <div> <button onClick={() => this.handleClick0()}>按钮0</button> <button onClick={() => this.handleClick1()}>按钮1</button> <button onClick={() => this.handleClick1()}>按钮2</button> <button id="btn4" onClick={() => this.handleClick1()}> 按钮3 </button> </div> ); } }