目录
1、this.setState的注意事项
2、是什么造成了this.setState()的不同步?
3、 那this.setState()什么时候同步,什么时候不同步?
3.1 经过React包装的onClick点击事件()
3.2 没经过React包装的 原生点击事件
1、this.setState的注意事项
this.setState(param1, param2);
param1: 对象或函数 --- 改变state的值
param2: 回调函数 --- 等待state更新后,执行的函数
项目中遇到类似这样的:
【问题】
发现 if 语句里拿不到type的值
【原因】
this.setState()不保证是同步的,所以在if条件中调用setState修改后的值,是做不到更新
的。
【解决】
利用this.setState()的第二个参数:回调函数,在等第一个参数内的state更新后再调用
【问题】
export default class A extends React.pureComponent {
constructor(props){
this.state={
type: '',
}
}
// 第一个参数:对象
onClick = () => {
this.setState({
type: 'asc'
});
if(this.state.type=== 'asc'){
console.log(this.state.type, '0') // ''
axios.post().then(res => {
console.log(res, 'res')
})
}
};
【解决】
// 第二个参数:回调函数,在等待第一个参数更新之后调用
onClick = () => {
this.setState({
type: 'asc', // 第一个参数: 改变state
}, () => {
if(this.state.type=== 'asc'){ // 第二个参数:回调函数,用改变后的state值do something
console.log(this.state.type, '0') // 'asc'
axios.post().then(res => {
console.log(res, 'res')
})
}
});
};
2、是什么造成了this.setState()的不同步?
React 的批处理更新导致的(batch the updates)
setState 其实本身执行的过程和代码都是同步的
React为了优化性能,setState()执行时会判断变量isBatchingUpdates的值是true or false, 然后决定是同步更新还是批量更新(从isBatchingUpdates这个变量名就可以直观的看出)
3、 那this.setState()什么时候同步,什么时候不同步?
由于isBatchingUpdates默认值是false,即默认是不批量更新的,是立即执行的,是同步的,一行执行完紧接着执行下一行。
但如果this.setState在React合成事件/钩子函数中,React会通过batchedUpdates()这个函数将isBatchingUpdates变成true,即批量更新的,不同步的。
所以主要看调用this.setState()的函数有没有被React包装过。图中左侧是没有包装,右侧是经过React包装的。如果没经过React包装(not managed by ReactJS), isBatchingUpdates就不会从false变为true,就是同步更新的,代码一行一行的执行
例子:
分别用两种方法绑定button的click事件,点击button的时候,改变state的值
3.1 经过React包装的onClick点击事件()
把这两次打印 console.log('prev state:', this.state.type)、console.log('current state:', this.state.type); 放到队列中,一起更新,所以第二次打印值与第一次打印值一样
};export default class A extends React.pureComponent { constructor(props) { super(props); this.state = { type: 'origin', // 原始值为 origin }; } changeState = e => { console.log('prev state:', this.state.type); this.setState({ type: 'changed', // 改变后为 changed }); console.log('current state:', this.state.type); }; render() { console.log('render3'); return ( <Button onClick={this.changeState}>改变state</Button> ); } }
打印结果:
isBatchingUpdates是true,批量更新的,是不同步的,把要执行的内容放到队列中,一起更新,所以第二次打印值与第一次打印值一样
3.2 没经过React包装的 原生点击事件
把这两次打印 console.log('prev state:', this.state.type)、console.log('current state:', this.state.type); 分别打印 ,所以第二次打印值与第一次打印值不一样
};export default class A extends React.pureComponent { constructor(props) { super(props); this.state = { type: 'origin', // 原始值为 origin }; } componentDidMount = e => { const dom = document.getElementById('btn'); dom.addEventListener('click', this.changeState); } changeState = e => { console.log('prev state:', this.state.type); this.setState({ type: 'changed', // 改变后为 changed }); console.log('current state:', this.state.type); }; render() { console.log('render'); return ( <Button id="btn">改变state</Button> ); } }
打印结果:
isBatchingUpdates是false,说明是同步更新的,一行执行完紧接着执行下一行。
(在输出prev state 这一行之后,遇到第二行的this.setState()就立即执行了,state更新之后就触发了render,然后才输出current state)
这个博主:
http://t.csdnimg.cn/gEM7x