首先了解一个造成不能立即生效的原因,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 (
按钮3
);
}
}