前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React源码解析之Update和UpdateQueue

React源码解析之Update和UpdateQueue

作者头像
进击的小进进
发布2019-09-05 17:21:43
1.1K0
发布2019-09-05 17:21:43
举报

一、Update 位置: Update位置如下( 详情请看React源码解析之ReactDOM.render() ): updateContainer()—> updateContainerAtExpirationTime()—> scheduleRootUpdate()—> createUpdate()

作用: (1)用来记录组件的状态变化 (2)存放在UpdateQueue中 (3)多个Update可以同时存在 比如设置三个setState()React是不会立即更新的,而是放到UpdateQueue中,再去更新

源码:

代码语言:javascript
复制
export const UpdateState = 0;
export const ReplaceState = 1;
export const ForceUpdate = 2;
export const CaptureUpdate = 3;

export function createUpdate(
  expirationTime: ExpirationTime,
  suspenseConfig: null | SuspenseConfig,
): Update<*> {
  return {
    //更新的过期时间
    expirationTime,
    suspenseConfig,

    // export const UpdateState = 0;
    // export const ReplaceState = 1;
    // export const ForceUpdate = 2;
    // export const CaptureUpdate = 3;

    //重点提下CaptureUpdate,在React16后有一个ErrorBoundaries功能
    //即在渲染过程中报错了,可以选择新的渲染状态(提示有错误的状态),来更新页面
    tag: UpdateState, //0更新 1替换 2强制更新 3捕获性的更新

    //更新内容,比如setState接收的第一个参数
    payload: null,

    //对应的回调,比如setState({}, callback )
    callback: null,

    //指向下一个更新
    next: null,

    //指向下一个side effect
    nextEffect: null,
  };
}

解析: update属性的解释均已写在代码中,需要注意的是 (1)tag的值为CaptureUpdate时,为捕获性更新,也就是在更新中捕获到错误时,渲染成错误状态

(2)多个updatepush进更新队列中,next属性指向下一节点

二、UpdateQueue 位置: UpdateQueue位置如下( 详情请看React源码解析之ReactDOM.render() ): updateContainer()—> updateContainerAtExpirationTime()—> scheduleRootUpdate()—> enqueueUpdate(current, update)——> createUpdateQueue()

作用: 依次执行内部的update

源码:

代码语言:javascript
复制
//创建更新队列
export function createUpdateQueue<State>(baseState: State): UpdateQueue<State> {
  const queue: UpdateQueue<State> = {
    //应用更新后的state
    baseState,
    //队列中的第一个update
    firstUpdate: null,
    //队列中的最后一个update
    lastUpdate: null,
    //队列中第一个捕获类型的update
    firstCapturedUpdate: null,
    //队列中最后一个捕获类型的update
    lastCapturedUpdate: null,
    //第一个side effect
    firstEffect: null,
    //最后一个side effect
    lastEffect: null,
    firstCapturedEffect: null,
    lastCapturedEffect: null,
  };
  return queue;
}

解析: (1)baseState在组件setState后,渲染并更新state,在下次更新时,拿的就是这次更新过的state

(2)firstUpdatelastUpdate之间的update通过上个updatenext串联

三、enqueueUpdate() 作用: 单向链表,用来存放updatenext来串联update

源码:

代码语言:javascript
复制
//每次setState都会update,每次update,都会入updateQueue
//current即fiber
export function enqueueUpdate<State>(fiber: Fiber, update: Update<State>) {
  // Update queues are created lazily.
  //alternate即workInProgress
  //fiber即current

  //current到alternate即workInProgress有一个映射关系
  //所以要保证current和workInProgress的updateQueue是一致的
  const alternate = fiber.alternate;
  //current的队列
  let queue1;
  //alternate的队列
  let queue2;
  //如果alternate为空
  if (alternate === null) {
    // There's only one fiber.
    queue1 = fiber.updateQueue;
    queue2 = null;
    //如果queue1仍为空,则初始化更新队列
    if (queue1 === null) {
      queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
    }
  } else {
    // There are two owners.
    //如果alternate不为空,则取各自的更新队列
    queue1 = fiber.updateQueue;
    queue2 = alternate.updateQueue;
    if (queue1 === null) {
      if (queue2 === null) {
        // Neither fiber has an update queue. Create new ones.
        //初始化
        queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
        queue2 = alternate.updateQueue = createUpdateQueue(
          alternate.memoizedState,
        );
      } else {
        // Only one fiber has an update queue. Clone to create a new one.
        //如果queue2存在但queue1不存在的话,则根据queue2复制queue1
        queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
      }
    } else {
      if (queue2 === null) {
        // Only one fiber has an update queue. Clone to create a new one.
        queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
      } else {
        // Both owners have an update queue.
      }
    }
  }
  if (queue2 === null || queue1 === queue2) {
    // There's only a single queue.
    //将update放入queue1中
    appendUpdateToQueue(queue1, update);
  } else {
    // There are two queues. We need to append the update to both queues,
    // while accounting for the persistent structure of the list — we don't
    // want the same update to be added multiple times.
    //react不想多次将同一个的update放入队列中
    //如果两个都是空队列,则添加update
    if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
      // One of the queues is not empty. We must add the update to both queues.
      appendUpdateToQueue(queue1, update);
      appendUpdateToQueue(queue2, update);
    }
    //如果两个都不是空队列,由于两个结构共享,所以只在queue1加入update
    //在queue2中,将lastUpdate指向update
    else {
      // Both queues are non-empty. The last update is the same in both lists,
      // because of structural sharing. So, only append to one of the lists.
      appendUpdateToQueue(queue1, update);
      // But we still need to update the `lastUpdate` pointer of queue2.
      queue2.lastUpdate = update;
    }
  }
}

解析: (1)queue1取的是fiber.updateQueue; queue2取的是alternate.updateQueue (2)如果两者均为null,则调用createUpdateQueue()获取初始队列 (3)如果两者之一为null,则调用cloneUpdateQueue()从对方中获取队列 (4)如果两者均不为null,则将update作为lastUpdate


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 webchen 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档