一、setState 的注意点
React 中的 setState 有三个注意点
- setState 并不会立即更新
- setState 会引发组件的重新绘制
- 多个 setState 会合并执行
这三个点也可以合在一起来说,首先,我们应该意识到,我们想要更新 state 的值,除了state本身的数值要改变,另外render也必须要执行,这才能让state的更新有意义。
setState与生命周期函数
setState的更新会引起生命周期发生变化。这4个函数依次被调用。
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
在 render函数被调用的时候,this.state才得到更新,即使 shouldComponentUpdate 返回了 false,state 也依旧会更新。
正是因为state会引起生命周期的变化,所以为了优化性能,React会把更新的 state 的操作 排成一个队列,一次性将对列中的state属性更新。
获取更新后的state的值
如果想获取更新后的state的值,可以使用setState的第二个参数,这个参数接收的是一个回调函数,这个回调函数会在界面渲染之后调用。
this.setState({
name: 'newName'
}, this.changeName);
changeName = () => {
const { name } = this.state;
console.log(name); // 'newName'
}
二、 setState的两种使用形式
对象形式的setState
this.setState({
name: 'newName'
});
函数形式的setState
// 第一种
this.setState((preState, props) => {
return {name: props.name}
});
// 第二种
this.setState((preState, props) => ({
name: preState.name
}));
三、setState 的更新状态
判断setState()更新状态时异步还是同步的,主要是看执行setState的位置
- 在React控制的回调函数中(生命周期钩子,react事件监听回调)这种情况是异步的。
- 在非react控制的异步回调函数中(定时器回调/原生事件监听回调/promise回调)这种情况是同步的。
异步
handleClick = () => {
this.setState({
num: 1
}, this.showNum)
console.log(this.state.num); // 0
}
showNum = () => {
console.log(this.state.num); // 1
}
同步
handleClick = () => {
setTimeout(() => {
console.log('setTimeout 更新之前:', this.state.num); // 0
this.setState(state => ({ num: state.num + 1 }))
console.log('setTimeout 更新之后:', this.state.num); // 1
})
}
四、setState多次调用的问题
两个函数式setState的情况(不会合并)
changeNum = () => {
console.log(this.state.count);
this.setState(state => ({ num: state.num + 1 }))
this.setState(state => ({ num: state.num + 1 }))
}
changeNum(); // 0
changeNum(); // 2
两个对象式setState的情况(会合并)
changeNum = () => {
console.log("222", this.state.num);
this.setState({num: this.state.num + 1})
this.setState({num: this.state.num + 1})
}
changeNum(); // 0
changeNum(); // 1
先函数式后对象式(会合并)
changeNum = () => {
console.log("222", this.state.num);
this.setState(state => ({ num: state.num + 1 }))
this.setState({num: this.state.num + 1})
}
changeNum(); // 0
changeNum(); // 1
先对象式后函数式(不会合并)
changeNum = () => {
console.log("222", this.state.num);
this.setState({num: this.state.num + 1})
this.setState(state => ({ num: state.num + 1 }))
}
changeNum(); // 0
changeNum(); // 2
总结
函数式传入的state总是能够获取到最新的state,但是对象式则不能,但是最后render只会更新一次。