react15-源码演化-组件更新setState(三)

组件更新

  • 组件更新判断逻辑如下图:
    在这里插入图片描述

1. 合并state

1.1. src/index.js

import React from './react';
import ReactDOM from './react-dom';
class Counter extends React.Component {
   
   
  constructor(props) {
   
   
    super(props);
    this.state = {
   
    number: 0 };
    setTimeout(() => {
   
   
      this.setState({
   
    number: this.state.number + 1 });
      console.log(this.state);
    }, 1000);
  }
  render() {
   
   
    return <div id={
   
   'counter' + this.state.number}>+</div>
  }
}
ReactDOM.render(
  <Counter />,
  document.getElementById('root')
);

1.2. src/react/component.js

//更新队列
export const updateQueue = {
   
   
  updaters: [],//要执行的updater对象
  isPending: false,//是否处于批量更新模式
};

class Updater {
   
   
  constructor(componentInstance) {
   
   
    this.componentInstance = componentInstance;//Updater和类组件1对1关系
    this.pendingStates = [];//更新如果批量的,先把状态暂存到数组,最后更新时统一合并
    this.nextProps = null;//新的属性对象
  }
  addState(partialState){
   
   
    this.pendingStates.push(partialState);//把新状态放入数组
    this.emitUpdate();
  }
  emitUpdate(nextProps){
   
   
    this.nextProps = nextProps;
    //如果有新属性对象 或者 队列处于‘休息’状态,直接更新
    if (nextProps || !updateQueue.isPending) {
   
   
      this.updateComponent();
    } else {
   
   //否则交给队列处理
      updateQueue.add(this);
    }
  }
  updateComponent(){
   
   
    let {
   
    componentInstance, pendingStates, nextProps } = this;
    if (nextProps || pendingStates.length > 0) {
   
   //长度大于0,有要合并的状态
      shouldUpdate(componentInstance, nextProps, this.getState());
    }
  }
  //合并及返回新的状态
  getState(){
   
   
    let {
   
    componentInstance, pendingStates } = this;
    let {
   
    state } = componentInstance;//老组件当前状态
    if (pendingStates.length > 0) {
   
   
      //迭代pendingStates,将所有状态合并到state
      for (let i = 0; i < pendingStates.length; i++) {
   
   
        let nextState = pendingStates[i];
        if (typeof nextState === 'function') {
   
   
          state = {
   
    ...state, ...nextState.call(componentInstance, state) };
        } else {
   
   
          state = {
   
    ...state, ...nextState };
        }
      }
    }
    pendingStates.length = 0;//合并后清空数组
    return state;
  }
}
//判断是否要更新
function shouldUpdate(componentInstance, nextProps, nextState) {
   
   
  componentInstance.props = nextProps;//将新props赋给组件
  componentInstance.state = nextState;//将新state赋给组件
  if (
    componentInstance.shouldComponentUpdate &&
    !componentInstance.shouldComponentUpdate(nextProps, nextState)
  ) {
   
   
    //如果shouldComponentUpdate返回false,则不更新
    return false;
  }
  componentInstance.forceUpdate();//让组件强制更新
}

class Component {
   
   
  constructor(props) {
   
   
    this.props = props;
    this.$updater = new Updater(this); //this 就是类组件的实例
    this.state = {
   
   }; // 当前状态
    this.nextProps = null; // 下一个属性对象
  }
  //批量更新 partial,状态可能会被合并
  setState(partialState) {
   
   
    this.$updater.addState(partialState);
  }
  forceUpdate(){
   
   //进行组件更新
  }
}
//类组件的本质也是函数(请参考new Class原理),通过`isReactComponent`判断是类组件还是函数组件
Component.prototype.isReactComponent = {
   
   };
export {
   
   
  Component
}

2. 简单替换DOM

2.1. src/react/component.js

import {
   
    compareTwoElements } from './vdom';

//更新队列
export const updateQueue = {
   
   
  updaters: [],//要执行的updater对象
  isPending: false,//是否处于批量更新模式
};

class Updater {
   
   
  constructor(componentInstance) {
   
   
    this.componentInstance = componentInstance;//Updater和类组件1对1关系
    this.pendingStates = [];//更新如果批量的,先把状态暂存到数组,最后更新时统一合并
    this.nextProps = null;//新的属性对象
  }
  addState(partialState){
   
   
    this.pendingStates.push(partialState);//把新状态放入数组
    this.emitUpdate();
  }
  emitUpdate(nextProps){
   
   
    this.nextProps = nextProps;
    //如果有新属性对象 或者 队列处于‘休息’状态,直接更新
    if (nextProps || !updateQueue.isPending) {
   
   
      this.updateComponent();
    } else {
   
   //否则交给队列处理
      updateQueue.add(this);
    }
  }
  updateComponent(){
   
   
    let {
   
    componentInstance, pendingStates, nextProps } = this;
    if (nextProps || pendingStates.length > 0) {
   
   //长度大于0,有要合并的状态
      shouldUpdate(componentInstance, nextProps, this.getState());
    }
  }
  //合并及返回新的状态
  getState(){
   
   
    let {
   
    componentInstance, pendingStates } = this;
    let {
   
    state } = componentInstance;//老组件当前状态
    if (pendingStates.length > 0) {
   
   
      //迭代pendingStates,将所有状态合并到state
      for (let i = 0; i < pendingStates.length; i++) {
   
   
        let nextState = pendingStates[i];
        if (typeof nextState === 'function') {
   
   
          state = {
   
    ...state, ...nextState.call(componentInstance, state) };
        } else {
   
   
          state = {
   
    ...state, ...nextState };
        }
      }
    }
    pendingStates.length = 0;//合并后清空数组
    return state;
  }
}
//判断是否要更新
function shouldUpdate(componentInstance, nextProps, nextState) {
   
   
  componentInstance.props = nextProps;//将新props赋给组件
  componentInstance.state = nextState;//将新state赋给组件
  if (
    componentInstance.shouldComponentUpdate &&
    !componentInstance.shouldComponentUpdate(nextProps, nextState)
  ) {
   
   
    //如果shouldComponentUpdate返回false,则不更新
    return false;
  }
  componentInstance.forceUpdate();//让组件强制更新
}

class Component {
   
   
  constructor(props) {
   
   
    this.props = props;
    this.$updater = new Updater(this); //this 就是类组件的实例
    this.state = {
   
   }; // 当前状态
    this.nextProps = null; // 下一个属性对象
  }
  //批量更新 partial,状态可能会被合并
  setState(partialState) {
   
   
    this.$updater.addState(partialState);
  }
  forceUpdate(){
   
   //进行组件更新
    let {
   
    props, state, renderElement: oldRenderElement } = this;
    if (this.componentWillUpdate) {
   
   
      this.componentWillUpdate();
    }
    let newRenderElement = this.render();
    let currentElement = compareTwoElements(oldRenderElement, newRenderElement);
    this.renderElement = currentElement;
    if (this.componentDidUpdate) {
   
   
      this.componentDidUpdate();
    }
  }
}
//类组件的本质也是函数(请参考new Class原理),通过`isReactComponent`判断是类组件还是函数组件
Component.prototype.isReactComponent = {
   
   };
export {
   
   
  Component
}

2.2. src/react/vdom.js

import {
   
    TEXT, ELEMENT, CLASS_COMPONENT, FUNCTION_COMPONENT } from './constants';
import {
   
    setProps, onlyOne, flatten } from './utils';

export function compareTwoElements(oldRenderElement, newRenderElement) {
   
   
  oldRenderElement = onlyOne(oldRenderElement);
  newRenderElement = onlyOne(newRenderElement);
  let currentDOM = oldRenderElement.dom;//取出老的DOM节点(此处,element.dom = dom;已经做过预埋设计)
  let currentElement = oldRenderElement;
  if (newRenderElement == null) {
   
   
    currentDOM.parentNode.removeChild(currentDOM);//新的虚拟DOM为null,删掉老节点
    currentDOM 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值