this.setState的注意事项

目录

 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这个变量名就可以直观的看出)

                this.setState的注意事项_第1张图片

3、 那this.setState()什么时候同步,什么时候不同步?

由于isBatchingUpdates默认值是false,即默认是不批量更新的,是立即执行的,是同步的,一行执行完紧接着执行下一行。

但如果this.setState在React合成事件/钩子函数中,React会通过batchedUpdates()这个函数将isBatchingUpdates变成true,即批量更新的,不同步的。


        this.setState的注意事项_第2张图片

所以主要看调用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 (
      
    );
  }

}

        打印结果:

        this.setState的注意事项_第3张图片

       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 (
      
    );
  }

}

        打印结果:

        this.setState的注意事项_第4张图片

isBatchingUpdates是false,说明是同步更新的,一行执行完紧接着执行下一行。
(在输出prev state 这一行之后,遇到第二行的this.setState()就立即执行了,state更新之后就触发了render,然后才输出current state)

这个博主:

http://t.csdnimg.cn/gEM7x

你可能感兴趣的:(javascript,前端,react.js)