美文网首页react前端面试React
react 常见setState的原理解析

react 常见setState的原理解析

作者: majunchang | 来源:发表于2018-05-03 10:33 被阅读102次

    React.setState

    首先引入一个栗子

    class Example extends React.Component {
      constructor() {
        super();
        this.state = {
          val: 0
        };
      }
      
      componentDidMount() {
        this.setState({val: this.state.val + 1});
        console.log(this.state.val);    // 第 1 次 log
    
        this.setState({val: this.state.val + 1});
        console.log(this.state.val);    // 第 2 次 log
    
        setTimeout(() => {
          this.setState({val: this.state.val + 1});
          console.log(this.state.val);  // 第 3 次 log
    
          this.setState({val: this.state.val + 1});
          console.log(this.state.val);  // 第 4 次 log
        }, 0);
      }
      render() {
        return null;
      }
    };
    

    4次log的值 分别为 0 0 2 3

    setState 干了什么

    image

    说一下批量更新

    image

    解读为什么直接修改this.state无效

    要知道setState本质是通过一个队列机制实现state更新的。 执行setState时,会将需要更新的state合并后放入状态队列,而不会立刻更新state,队列机制可以批量更新state。
    如果不通过setState而直接修改this.state,那么这个state不会放入状态队列中,下次调用setState时对状态队列进行合并时,会忽略之前直接被修改的state,这样我们就无法合并了,而且实际也没有把你想要的state更新上去。

    什么是批量更新 Batch Update

    在一些mv*框架中,,就是将一段时间内对model的修改批量更新到view的机制。比如那前端比较火的React、vue(nextTick机制,视图的更新以及实现)为例。

    vue的nextTick机制 https://www.cnblogs.com/hity-tt/p/6729118.html

    html5新特性变动观察器 http://www.cnblogs.com/jscode/p/3600060.html

    消息进程 http://www.ruanyifeng.com/blog/2013/10/event_loop.html

    vue的批量更新体现

    1. Mutation Observer(变动观察器)是监视DOM变动的接口。当DOM对象树发生任何变动时,Mutation Observer会得到通知。
    2. 概念上,它很接近事件。可以理解为,当DOM发生变动会触发Mutation Observer事件。但是,它与事件有一个本质不同:事件是同步触发,也就是说DOM发生变动立刻会触发相应的事件;
    3. Mutation Observer则是异步触发,DOM发生变动以后,并不会马上触发,而是要等到当前所有DOM操作都结束后才触发。
    4. 这样设计是为了应付DOM变动频繁的情况。举例来说,如果在文档中连续插入1000个段落(p元素),会连续触发1000个插入事件,执行每个事件的回调函数,这很可能造成浏览器的卡顿;
    5. 而Mutation Observer完全不同,只在1000个段落都插入结束后才会触发,而且只触发一次。

    setState之后发生的事情

    • 在官方的描述中,setState操作并不保证是同步的,也可以认为是异步的。
    • React在setState之后,会经对state进行diff,判断是否有改变,然后去diff dom决定是否要更新UI。如果这一系列过程立刻发生在每一个setState之后,就可能会有性能问题。
    • 在短时间内频繁setState。React会将state的改变压入栈中,在合适的时机,批量更新state和视图,达到提高性能的效果。

    总结

    1. 通过setState去更新this.state,不要直接操作this.state,请把它当成不可变的。
    2. 调用setState更新this.state不是马上生效的,它是异步滴,所以不要天真以为执行完setState后this.state就是最新的值了。
    3. 多个顺序执行的setState不是同步地一个一个执行滴,会一个一个加入队列,然后最后一起执行,即批处理

    如何知道state已经被更新

    传入回调函数

    setState({
        index: 1
    }}, function(){
        console.log(this.state.index);
    })
    

    在钩子函数中体现

    componentDidUpdate(){
        console.log(this.state.index);
    }
    

    setState的另外一种方式 (需要使用上一次的state的值)

    在setState的第一个参数中传入function,该function会被压入调用栈中,在state真正改变后,按顺序回调栈里面的function。该function的第一个参数为上一次更新后的state。这样就能确保你下一次的操作拿到的是你预期的值

    lass Com extends React.Component{
        constructor(props){
            super(props);
            this.state = {
                index: 0
            }
            this.add = this.add.bind(this);
        }
    
        add(){
            this.setState(prevState => {
                return {index: prevState.index + 1};
            });
            this.setState(prevState => {
                return {index: prevState.index + 1};
            });
        }
    }
    

    注意点

    1. setState可能会引发不必要的渲染(renders)
    2. setState无法完全掌控应用中所有组件的状态

    相关文章

      网友评论

      本文标题:react 常见setState的原理解析

      本文链接:https://www.haomeiwen.com/subject/xprkrftx.html