React:数据驱动视图(废弃)

2,299 阅读3分钟

数据驱动视图是什么?(单向数据流)

传统的jquery开发是通过操作dom来实现页面的渲染和交互,而React采用的是数据驱动视图的方式:view是基于数据来渲染的,数据一旦变化,view就会自动更新。因此我们在开发时,只需要关注数据即可,不用直接操作dom。

注意:React不是响应式设计,因为它需要通过this.setStateuseState等方式手动触发数据变化。

一、数据驱动视图原理

class Calculator extends React.Component {
    constructor(props) {
        super(props);
        this.state = {val: 0};
    }
    render() {
        return(
            <div className="container">
                <button onClick={ () => {
                    this.setState({val: 1})
                }}>Submit!</button>
            </div>
        )
    }
}

React通过setState实现数据驱动视图,通过setState引发一次组件的更新过程从而实现页面的重新渲染(除非shouldComponentUpdate返回false)。假设我们点击button触发了onClick事件,然后它对应的监听函数调用了this.setState()来改变数据,之后的操作过程为:

1. setState:dirtyComponent => 批量更新

  • pending:当前所有等待更新的state队列。
  • isBatchingUpdatesReact中用于标识当前是否处理批量更新状态,默认false
  • dirtyComponent:当前所有待更新state的组件队列。
  • pending队列中的state进行合并,得到最终要更新的state,并将pending队列置为空。(该方法的执行时机不确定,应该在事务结束后?)

处理过程:

  1. setState()首先将接收的第一个参数state存储在pending队列中;(state)
  2. 判断当前React是否处于批量更新状态,是的话就将需要更新state的组件添加到dirtyComponents中;(组件)
  3. 不是的话,它会遍历dirtyComponents的所有组件,调用updateComponent方法更新每个dirty组件(开启批量更新事务),每个组件有:

2. 执行更新阶段的生命周期 => dirty组件的更新

调用setState会默认调用组件更新阶段的5个生命周期,依次是:

  • 执行生命周期getDerivedStateFromProps
  • 执行生命周期shouldComponentUpdate,根据返回值判断是否要继续更新。
  • 执行生命周期render:执行真正的更新。
  • 执行生命周期getSnapshotBeforeUpdate
  • 执行生命周期componentDidUpdate

3. render:重新构建虚拟dom树,执行 diff 并更新到真实dom => view更新

我们知道在React的生命周期里,无论是挂载还是更新阶段,在render之前的生命周期函数都不会更新this.stateprops,直到render执行完成后,数据才会更新。(只有shouldComponentUpdate返回false时例外,此时会中断更新过程,但依然会更新this.state

3.1 虚拟dom树:dirty组件的组件树

  1. jsx 通过 babel 转换成 React.createElement;
  2. createElement()函数返回了一个了ReactElement函数;
  3. ReactElement函数返回的对象就是虚拟dom(Fiber 链表结构);
  4. Fiber节点通过return、child、sibling属性连接成Fiber Tree

当state或props改变时,会再次调用render生成一个虚拟dom树。

3.2 diff:批量更新,使虚拟dom和真实dom保持同步

比较新旧两个虚拟dom树,生成一个补丁,最后批量把补丁更新到真实dom上。

它会把收集到的多个补丁集暂存到队列中,最终实现集中的dom批量更新。

协调Reconciliation过程是将虚拟dom和真实dom保持同步,它包含diff算法,但它加了一些启发规则。

二、事务:react 17已经删除