Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

setState和forceUpdate #56

Open
Cosen95 opened this issue Oct 27, 2020 · 0 comments
Open

setState和forceUpdate #56

Cosen95 opened this issue Oct 27, 2020 · 0 comments

Comments

@Cosen95
Copy link
Owner

Cosen95 commented Oct 27, 2020

setState

setState的定义在packages/react/src/ReactBaseClasses.js

/**
 * @param {object|function} partialState Next partial state or function to
 *        produce next partial state to be merged with current state.
 * @param {?function} callback Called after state is updated.
 * @final
 * @protected
 */
Component.prototype.setState = function (partialState, callback) {
  invariant(
    typeof partialState === "object" ||
      typeof partialState === "function" ||
      partialState == null,
    "setState(...): takes an object of state variables to update or a " +
      "function which returns an object of state variables."
  );
  this.updater.enqueueSetState(this, partialState, callback, "setState");
};

可以看到内部调用了enqueueSetState

// packages/react-reconciler/src/ReactFiberClassComponent.js
// classComponent初始化的时候拿到的update对象
const classComponentUpdater = {
  isMounted,
  enqueueSetState(inst, payload, callback) {
    // inst即调用this.setState时传进来的this,也就是classComponent实例

    // 通过this获取fiber对象
    // this._reactInternalFiber
    // this本身有存储 fiber对象 的属性,叫 _reactInternalFiber

    const fiber = getInstance(inst);
    // 计算当前时间
    const currentTime = requestCurrentTime();
    // 计算fiber对象的过期时间
    const expirationTime = computeExpirationForFiber(currentTime, fiber);
    // 创建update对象
    const update = createUpdate(expirationTime);
    // setState传进来的要更新的对象
    update.payload = payload;
    // callback就是setState({},()=>{})的回调函数
    if (callback !== undefined && callback !== null) {
      if (__DEV__) {
        warnOnInvalidCallback(callback, "setState");
      }
      update.callback = callback;
    }
    flushPassiveEffects();
    // update入队
    enqueueUpdate(fiber, update);
    // 任务调度
    scheduleWork(fiber, expirationTime);
  },
  // ...
};

enqueueSetState函数的作用是:给React节点的fiber对象创建update,并将该更新对象入队

传入的inst即调用this.setState时传进来的this,也就是classComponent实例。

通过getInstance方法来获取目标对象的_reactInternalFiber属性。

下面依次拿到currentTimeexpirationTime,然后通过createUpdate来创建update对象。

最后update入队、进入任务调度。

接着来看下forceUpdate

forceUpdate

定义同样在packages/react/src/ReactBaseClasses.js

/**
 * Forces an update. This should only be invoked when it is known with
 * certainty that we are **not** in a DOM transaction.
 *
 * You may want to call this when you know that some deeper aspect of the
 * component's state has changed but `setState` was not called.
 *
 * This will not invoke `shouldComponentUpdate`, but it will invoke
 * `componentWillUpdate` and `componentDidUpdate`.
 *
 * @param {?function} callback Called after update is complete.
 * @final
 * @protected
 */
Component.prototype.forceUpdate = function (callback) {
  this.updater.enqueueForceUpdate(this, callback, "forceUpdate");
};

内部调用了enqueueForceUpdate方法:

 enqueueForceUpdate(inst, callback) {
    const fiber = getInstance(inst);
    const currentTime = requestCurrentTime();
    const expirationTime = computeExpirationForFiber(currentTime, fiber);

    const update = createUpdate(expirationTime);
    update.tag = ForceUpdate;

    if (callback !== undefined && callback !== null) {
      if (__DEV__) {
        warnOnInvalidCallback(callback, 'forceUpdate');
      }
      update.callback = callback;
    }

    flushPassiveEffects();
    enqueueUpdate(fiber, update);
    scheduleWork(fiber, expirationTime);
  },

enqueueSetState()方法的流程类似,唯一不同的是多了个手动修改属性tag的值:

update.tag = ForceUpdate;

可以看到createUpdate()方法中,初始化的tag值是UpdateState

export const UpdateState = 0; // 更新
export const ReplaceState = 1; // 替换
export const ForceUpdate = 2; // 强制更新
export const CaptureUpdate = 3; // 捕获性的更新

export function createUpdate(expirationTime: ExpirationTime): Update<*> {
  return {
    expirationTime: expirationTime,
    // 重点提下CaptureUpdate,在React16后有一个ErrorBoundaries功能
    // 即在渲染过程中报错了,可以选择新的渲染状态(提示有错误的状态),来更新页面
    // 默认是0即更新
    tag: UpdateState,
    payload: null,
    callback: null,

    next: null,
    nextEffect: null,
  };
}

因此要改成ForceUpdate,以便React进行Update优先级排序。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant