分享

// 排除两种不符合预期的情况
// 1:-0 === +0
// 2: NaN !== NaN
function is(x: any, y: any) {
  return (
    (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y)
  );
}

性能上:无状态函数组件 > class components > React.createClass()

mixin用的是for in,会复制原型链上的属性,Object.assign不会

mixin的用法:

var ComponentOne = React.createClass({
	mixins: [DefaultNameMixin],
})

useState的简单实现

let memoizedState: any[] = [] // hooks 的值存放在这个数组里
let cursor = 0 // 当前 memoizedState 的索引

function useState(initialValue: any) {
    memoizedState[cursor] = memoizedState[cursor] || initialValue
    const currentCursor = cursor
    function setState(newState: any) {
        memoizedState[currentCursor] = newState
        cursor = 0
        render(<App />, document.getElementById('root'))
    }
    // 返回当前 state,并把 cursor 加 1
    return [memoizedState[cursor++], setState] 
}

并发模式

1, 同步代码 和 promise 里的 setState 会合并
2, 同时间点的 setTimeout 里的 setState 会合并

更新的优先级

1,useEffect(默认&回调)| promise | setTimeout: 97
2,click(用户交互): 98
3,渲染过程中更新(立即更新):99

hooks type:

export type Hook = {
  memoizedState: any, // 指向当前渲染节点 Fiber, 上一次完整更新之后的最终状态值

  baseState: any, // 初始化 initialState, 已经每次 dispatch 之后 newState
  baseUpdate: Update<any, any> | null, // 当前需要更新的 Update ,每次更新完之后,会赋值上一个 update,方便 react 在渲染错误的边缘,数据回溯
  queue: UpdateQueue<any, any> | null, // 缓存的更新队列,存储多次更新行为

  next: Hook | null,  // link 到下一个 hooks,通过 next 串联每一 hooks
};

type Update<S, A> = {
  expirationTime: ExpirationTime, // 当前更新的过期时间
  suspenseConfig: null | SuspenseConfig,
  action: A,
  eagerReducer: ((S, A) => S) | null,
  eagerState: S | null,
  next: Update<S, A> | null,

  priority?: ReactPriorityLevel,  // 优先级
};

type UpdateQueue<S, A> = {
  last: Update<S, A> | null,
  dispatch: (A => mixed) | null,
    lastRenderedReducer: ((S, A) => S) | null,
      lastRenderedState: S | null,
};

HooksDispatcherOnMount 和 HooksDispatcherOnUpdate

const HooksDispatcherOnMount: Dispatcher = {
  readContext,

  useCallback: mountCallback,
  useContext: readContext,
  useEffect: mountEffect,
  useImperativeHandle: mountImperativeHandle,
  useLayoutEffect: mountLayoutEffect,
  useMemo: mountMemo,
  useReducer: mountReducer,
  useRef: mountRef,
  useState: mountState,
  useDebugValue: mountDebugValue,
  useResponder: createResponderListener,
};

const HooksDispatcherOnUpdate: Dispatcher = {
  readContext,

  useCallback: updateCallback,
  useContext: readContext,
  useEffect: updateEffect,
  useImperativeHandle: updateImperativeHandle,
  useLayoutEffect: updateLayoutEffect,
  useMemo: updateMemo,
  useReducer: updateReducer,
  useRef: updateRef,
  useState: updateState,
  useDebugValue: updateDebugValue,
  useResponder: createResponderListener,
};

beginWork

// function beginWork
case IndeterminateComponent:
        {
          return mountIndeterminateComponent(current, workInProgress, workInProgress.type, renderExpirationTime);
        }
case FunctionComponent: {
      // TODO: 这里会将 workInProgress 上的 memoizedState(最新的 hook)拷贝赋值给 current.memoizedState
      return updateFunctionComponent(
        current,
        workInProgress,
        Component,
        resolvedProps,
        renderExpirationTime,
      );
    }

mountIndeterminateComponent

function mountIndeterminateComponent(_current, workInProgress, Component, renderExpirationTime) {
 // if (_current !== null) {
 //   _current.alternate = null;
 //   workInProgress.alternate = null;

 //   workInProgress.effectTag |= Placement;
 // }

 // var props = workInProgress.pendingProps;
 // var context;

 // {
 //   var unmaskedContext = getUnmaskedContext(workInProgress, Component, false);
 //   context = getMaskedContext(workInProgress, unmaskedContext);
 // }

 // prepareToReadContext(workInProgress, renderExpirationTime);
 // var value;

 // {
 //   if (Component.prototype && typeof Component.prototype.render === 'function') {
 //     var componentName = getComponentName(Component) || 'Unknown';

 //     if (!didWarnAboutBadClass[componentName]) {
 //       error("The <%s /> component appears to have a render method, but doesn't extend React.Component. " + 'This is likely to cause errors. Change %s to extend React.Component instead.', componentName, componentName);

 //       didWarnAboutBadClass[componentName] = true;
 //     }
 //   }

 //   if (workInProgress.mode & StrictMode) {
 //     ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null);
 //   }

 //   setIsRendering(true);
 //   ReactCurrentOwner$1.current = workInProgress;
   value = renderWithHooks(null, workInProgress, Component, props, context, renderExpirationTime);
 //   setIsRendering(false);
 // }


 // workInProgress.effectTag |= PerformedWork;

  if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
 //   {
 //     var _componentName = getComponentName(Component) || 'Unknown';

 //     if (!didWarnAboutModulePatternComponent[_componentName]) {
 //       error('The <%s /> component appears to be a function component that returns a class instance. ' + 'Change %s to a class that extends React.Component instead. ' + "If you can't use a class try assigning the prototype on the function as a workaround. " + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + 'cannot be called with `new` by React.', _componentName, _componentName, _componentName);

 //       didWarnAboutModulePatternComponent[_componentName] = true;
 //     }
 //   } // Proceed under the assumption that this is a class instance


    workInProgress.tag = ClassComponent; // Throw out any hooks that were used.

 //   workInProgress.memoizedState = null;
 //   workInProgress.updateQueue = null; // Push context providers early to prevent context stack mismatches.
 //   // During mounting we don't know the child context yet as the instance doesn't exist.
 //   // We will invalidate the child context in finishClassComponent() right after rendering.

 //   var hasContext = false;

 //   if (isContextProvider(Component)) {
 //     hasContext = true;
 //     pushContextProvider(workInProgress);
 //   } else {
 //     hasContext = false;
 //   }

 //   workInProgress.memoizedState = value.state !== null && value.state !== undefined ? value.state : null;
 //   initializeUpdateQueue(workInProgress);
 //   var getDerivedStateFromProps = Component.getDerivedStateFromProps;

 //   if (typeof getDerivedStateFromProps === 'function') {
 //     applyDerivedStateFromProps(workInProgress, Component, getDerivedStateFromProps, props);
 //   }

 //   adoptClassInstance(workInProgress, value);
 //   mountClassInstance(workInProgress, Component, props, renderExpirationTime);
 //   return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime);
  } else {
 	// TODO:标记组件为函数组件
    workInProgress.tag = FunctionComponent;

 //   {

 //     if ( workInProgress.mode & StrictMode) {
 //       // Only double-render components with Hooks
 //       if (workInProgress.memoizedState !== null) {
 //         value = renderWithHooks(null, workInProgress, Component, props, context, renderExpirationTime);
 //       }
 //     }
 //   }

 //   reconcileChildren(null, workInProgress, value, renderExpirationTime);

 //   {
 //     validateFunctionComponentInDev(workInProgress, Component);
 //   }

 //   return workInProgress.child;
  }
}

renderWithHooks

// 首次加载或者更新
nextCurrentHook = current !== null ? current.memoizedState : null;
ReactCurrentDispatcher.current =
      nextCurrentHook === null
        ? HooksDispatcherOnMount
        : HooksDispatcherOnUpdate;
// mountState 和 updateState

// 完整代码
// current 为旧的 Fiber对象,第一次挂载 state 时为null,workInProgress 为新的Fiber对象,两者使用了 双缓冲技术,分别保留对方的引用
// workInProgress.alternate = current;
// current.alternate = workInProgress;
// TODO:在之后的 更新中都是在 workInProgress 上操作,更新完成后会把 current 指向 workInProgress
function renderWithHooks(current, workInProgress, Component, props, secondArg, nextRenderExpirationTime) {
    renderExpirationTime = nextRenderExpirationTime;
    // TODO: 把 workInProgress 赋值给 当前正在渲染 的 fiber
    currentlyRenderingFiber$1 = workInProgress;
/*
    {
      hookTypesDev = current !== null ? current._debugHookTypes : null;
      hookTypesUpdateIndexDev = -1; // Used for hot reloading:

      ignorePreviousDependencies = current !== null && current.type !== workInProgress.type;
    }
    */

	// TODO: 清除 workInProgress.memoizedState
    workInProgress.memoizedState = null;
    workInProgress.updateQueue = null;
    workInProgress.expirationTime = NoWork;

    {
      if (current !== null && current.memoizedState !== null) {
        ReactCurrentDispatcher.current = HooksDispatcherOnUpdateInDEV;
      } else if (hookTypesDev !== null) {
        ReactCurrentDispatcher.current = HooksDispatcherOnMountWithHookTypesInDEV;
      } else {
        ReactCurrentDispatcher.current = HooksDispatcherOnMountInDEV;
      }
    }

    var children = Component(props, secondArg);

	// TODO: 渲染函数内更新 入口
    if (workInProgress.expirationTime === renderExpirationTime) {
      var numberOfReRenders = 0;

      do {
        workInProgress.expirationTime = NoWork;

		// TODO: 最大可更新次数 RE_RENDER_LIMIT 为 25
        if (!(numberOfReRenders < RE_RENDER_LIMIT)) {
          {
            throw Error( "Too many re-renders. React limits the number of renders to prevent an infinite loop." );
          }
        }

        numberOfReRenders += 1;

/*
        {
          ignorePreviousDependencies = false;
        }
*/
		// TODO: 把这些变量都置空,方便在 updateWorkInProgressHook 重新获取 新旧的hook
        currentHook = null;
        workInProgressHook = null;
        workInProgress.updateQueue = null;
/*
        {
          // Also validate hook order for cascading updates.
          hookTypesUpdateIndexDev = -1;
        }
 */

		// TODO: 指定新的 useState 为 rerenderState
        ReactCurrentDispatcher.current =  HooksDispatcherOnRerenderInDEV ;
        // TODO: 用新 useState 重新渲染组件
        children = Component(props, secondArg);
      } while (workInProgress.expirationTime === renderExpirationTime);
    }

  // TODO: 把 dispatcher 指向 ContextOnlyDispatcher(只能调用reacContext,调用 hook 的其它方法都会报错
  ReactCurrentDispatcher.current = ContextOnlyDispatcher;

/*
  {
      workInProgress._debugHookTypes = hookTypesDev;
    } // This check uses currentHook so that it works the same in DEV and prod bundles.
    // hookTypesDev could catch more cases (e.g. context) but only in DEV bundles.
*/

	// TODO: 判断是否渲染完所有 hook
    var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null;
    renderExpirationTime = NoWork;
    currentlyRenderingFiber$1 = null;
    currentHook = null;
    workInProgressHook = null;
/*
    {
      currentHookNameInDev = null;
      hookTypesDev = null;
      hookTypesUpdateIndexDev = -1;
    }
*/
    didScheduleRenderPhaseUpdate = false;

    if (!!didRenderTooFewHooks) {
      {
        throw Error( "Rendered fewer hooks than expected. This may be caused by an accidental early return statement." );
      }
    }

    return children;
}

ContextOnlyDispatcher

var ContextOnlyDispatcher = {
    readContext: readContext,
    useCallback: throwInvalidHookError,
    useContext: throwInvalidHookError,
    useEffect: throwInvalidHookError,
    useImperativeHandle: throwInvalidHookError,
    useLayoutEffect: throwInvalidHookError,
    useMemo: throwInvalidHookError,
    useReducer: throwInvalidHookError,
    useRef: throwInvalidHookError,
    useState: throwInvalidHookError,
    useDebugValue: throwInvalidHookError,
    useResponder: throwInvalidHookError,
    useDeferredValue: throwInvalidHookError,
    useTransition: throwInvalidHookError
  };

mountState

// TODO: 第一次调用组件的 useState 时实际调用的方法
function mountState(initialState) {
    var hook = mountWorkInProgressHook();

    // TODO: 如果是函数 就计算值
    if (typeof initialState === 'function') {
      initialState = initialState();
    }

    hook.memoizedState = hook.baseState = initialState;
    var queue = hook.queue = {
      pending: null,
      dispatch: null,
      // TODO: 计算其 值 的函数
      lastRenderedReducer: basicStateReducer,
      lastRenderedState: initialState
    };
    // TODO: 在之后的更新中: currentlyRenderingFiber$1 用于区分组件,queue 用于区分 hook
    var dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingFiber$1, queue);
    return [hook.memoizedState, dispatch];
  }

basicStateReducer

function basicStateReducer(state, action) {
   return typeof action === 'function' ? action(state) : action;
 }

mountWorkInProgressHook

// TODO: 创建一个新的 hook
function mountWorkInProgressHook() {
  var hook = {
    // TODO: 记录当前 useState 应该返回的值
    memoizedState: null,
	// TODO: 处理更新时,从这里获取初始值
    baseState: null,
    // TODO: 保存还没有提交的更新(可能是因为 更新的优先级 太低);假如新Fiber上的更新没有提交
    baseQueue: null,
    // TODO: 更新行为{dispatch, lastRenderReducer, lastRenderState, pending}
    queue: null,
    // TODO: 下一次 useState 对应的 Hook
    next: null,
  };

  // TODO: workInProgressHook 当前 hook(全局变量)
  // TODO: 只有在挂载第一个 state 的时候,workInProgressHook 为空
  // TODO: 其他时候 workInProgressHook 为上次执行的 hook
  if (workInProgressHook === null) {
    // TODO: 会把第一个hook 绑定到当前 fiber对象 的 memoizedState 上,更新时从这里开始读取
    currentlyRenderingFiber$1.memoizedState = workInProgressHook = hook;
  } else {
    // TODO: 上次执行的 hook 的 next 指向 当前hook
    workInProgressHook = workInProgressHook.next = hook;
  }

  return workInProgressHook;
}

dispatchAction

function dispatchAction(fiber, queue, action) {
    {
      // TODO: 不支持传入回调函数
      if (typeof arguments[3] === 'function') {
        error("State updates from the useState() and useReducer() Hooks don't support the " + 'second callback argument. To execute a side effect after ' + 'rendering, declare it in the component body with useEffect().');
      }
    }

    var currentTime = requestCurrentTimeForUpdate();
    var suspenseConfig = requestCurrentSuspenseConfig();
    var expirationTime = computeExpirationForFiber(currentTime, fiber, suspenseConfig);
    var update = {
      // TODO: 有效时间
      expirationTime: expirationTime,
      suspenseConfig: suspenseConfig,
      action: action,
      eagerReducer: null,
      eagerState: null,
      next: null
    };

    {
      update.priority = getCurrentPriorityLevel();
    }

    var pending = queue.pending;

    if (pending === null) {
      // TODO: 创建一个闭环
      update.next = update;
    } else {
      // TODO: 向环中插入新节点
      update.next = pending.next;
      pending.next = update;
    }

    queue.pending = update;
    var alternate = fiber.alternate;

	// TODO: 渲染函数中执行 setState
    if (fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1) {
      // TODO: 在其它操作(如 resetHooksAfterThrow)中作为判断标识
      didScheduleRenderPhaseUpdate = true;
      update.expirationTime = renderExpirationTime;
      // TODO: 设置当前 fiber 的更新时间,作为之后 判断 是否有立即更新 操作
      currentlyRenderingFiber$1.expirationTime = renderExpirationTime;
    } else {
      // TODO: 只有第一次更新时第一个 alternate 才为null(两次合并的更新 alternate 都为 null,但 fiber.expirationTime 可能!== NoWork=0,也只有这一次会提前计算新值,其它更新都是在 updateReducer 中计算
      // TODO: 如果一次更新中Fiber实际无更新 fiber.expirationTime 会变为 0,且 alternate.expirationTime 也为0,所以下次更新时会再次进入该分支
      if (fiber.expirationTime === NoWork && (alternate === null || alternate.expirationTime === NoWork)) {
        var lastRenderedReducer = queue.lastRenderedReducer;

        if (lastRenderedReducer !== null) {
          var prevDispatcher;

          {
          	// TODO: 暂存 ReactCurrentDispatcher.current 计算完新值后 恢复
            prevDispatcher = ReactCurrentDispatcher.current;
            ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
          }

          try {
            var currentState = queue.lastRenderedState;
            // TODO: 根据最近一次的 reducer 和最近一次的 state 值计算最新的 state 值,如果在进入render阶段前reducer没有变化那么可以复用eagerState而不用重新再次调用reducer
            var eagerState = lastRenderedReducer(currentState, action);

            update.eagerReducer = lastRenderedReducer;
            update.eagerState = eagerState;

			// TODO: 这里检测没有更新会直接返回,如果没有进入这里的无更新操作还是会进入 updateState
            if (objectIs(eagerState, currentState)) {
              return;
            }
          } catch (error) {
          } finally {
            {
              // TODO: 恢复 ReactCurrentDispatcher.current
              ReactCurrentDispatcher.current = prevDispatcher;
            }
          }
        }
      }
/*
      {
        if ('undefined' !== typeof jest) {
          warnIfNotScopedWithMatchingAct(fiber);
          warnIfNotCurrentlyActingUpdatesInDev(fiber);
        }
      }
*/
	  // TODO: 会更新 fiber 的 expirationTime
      scheduleWork(fiber, expirationTime);
    }
  }

getCurrentPriorityLevel

function getCurrentPriorityLevel() {
   switch (Scheduler_getCurrentPriorityLevel()) {
     case Scheduler_ImmediatePriority:
       return ImmediatePriority;

     case Scheduler_UserBlockingPriority:
       return UserBlockingPriority$1;

     case Scheduler_NormalPriority:
       return NormalPriority;

     case Scheduler_LowPriority:
       return LowPriority;

     case Scheduler_IdlePriority:
       return IdlePriority;

     default:
       {
         {
           throw Error( "Unknown priority level." );
         }
       }

   }
 }

updateFunctionComponent

function updateFunctionComponent(current, workInProgress, Component, nextProps, renderExpirationTime) {
/*
    {
      if (workInProgress.type !== workInProgress.elementType) {
        var innerPropTypes = Component.propTypes;

        if (innerPropTypes) {
          checkPropTypes_1(innerPropTypes, nextProps, // Resolved props
          'prop', getComponentName(Component), getCurrentFiberStackInDev);
        }
      }
    }

    var context;

    {
      var unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
      context = getMaskedContext(workInProgress, unmaskedContext);
    }

    var nextChildren;
    prepareToReadContext(workInProgress, renderExpirationTime);
*/
    {
      ReactCurrentOwner$1.current = workInProgress;
      setIsRendering(true);
      nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, context, renderExpirationTime);

	  // TODO: blocking模式 或 concurrent 模式 加上严格模式 会进入, 会执行两次 renderWithHooks ,流程基本一致 但只会触发 一次 useEffect
      if ( workInProgress.mode & StrictMode) {
        // TODO: workInProgress.memoizedState 时 更新后 的 最新 hook
        if (workInProgress.memoizedState !== null) {
          nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, context, renderExpirationTime);
        }
      }

      setIsRendering(false);
    }

	// TODO: 没有涉及更新
    if (current !== null && !didReceiveUpdate) {
      // TODO: 将 current.expirationTime 设置为 0
      bailoutHooks(current, workInProgress, renderExpirationTime);
      return bailoutOnAlreadyFinishedWork(current, workInProgress, renderExpirationTime);
    }

/*
    workInProgress.effectTag |= PerformedWork;
    reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime);
*/
	// TODO: 继续更新子节点
    return workInProgress.child;
  }

updateState

function updateState(initialState) {
  // TODO: state 都是用的 相同的 reducer 函数
  return updateReducer(basicStateReducer, initialState);
}

updateReducer

function updateReducer(reducer, initialArg, init) {
    // TODO: 获取当前正在工作中的 hook,并根据此创建一个新的hook(next 指向 null,其他的不变)
    var hook = updateWorkInProgressHook();
    var queue = hook.queue;

    if (!(queue !== null)) {
      {
        throw Error( "Should have a queue. This is likely a bug in React. Please file an issue." );
      }
    }

    // TODO: useState 情况下,两者是相等的
    queue.lastRenderedReducer = reducer;
    // TODO: 这里获取的时 旧Fiber 上的 hook
    var current = currentHook;

	// TODO: 还没有提交的更新(低优先级等)
    var baseQueue = current.baseQueue;

    var pendingQueue = queue.pending;

    if (pendingQueue !== null) {
      if (baseQueue !== null) {
      	// TODO: 合并两个环
        var baseFirst = baseQueue.next;
        var pendingFirst = pendingQueue.next;
        baseQueue.next = pendingFirst;
        pendingQueue.next = baseFirst;
      }
	  // TODO: 会将更新队列作为记录保存在 旧Fiber 上
      current.baseQueue = baseQueue = pendingQueue;
      queue.pending = null;
    }

    if (baseQueue !== null) {
      // TODO: 从环的第二个节点开始,第一个节点为最后一次更新
      var first = baseQueue.next;
      var newState = current.baseState;
      var newBaseState = null;
      var newBaseQueueFirst = null;
      var newBaseQueueLast = null;
      var update = first;

      do {
        var updateExpirationTime = update.expirationTime;

		// TODO: 超时了的更新
		/*
        if (updateExpirationTime < renderExpirationTime) {
          var clone = {
            expirationTime: update.expirationTime,
            suspenseConfig: update.suspenseConfig,
            action: update.action,
            eagerReducer: update.eagerReducer,
            eagerState: update.eagerState,
            next: null
          };

          if (newBaseQueueLast === null) {
            newBaseQueueFirst = newBaseQueueLast = clone;
            newBaseState = newState;
          } else {
            newBaseQueueLast = newBaseQueueLast.next = clone;
          }


          if (updateExpirationTime > currentlyRenderingFiber$1.expirationTime) {
            currentlyRenderingFiber$1.expirationTime = updateExpirationTime;
            markUnprocessedUpdateTime(updateExpirationTime);
          }
          */
        } else {
        /*
          // This update does have sufficient priority.
          if (newBaseQueueLast !== null) {
            var _clone = {
              expirationTime: Sync,
              suspenseConfig: update.suspenseConfig,
              action: update.action,
              eagerReducer: update.eagerReducer,
              eagerState: update.eagerState,
              next: null
            };
            newBaseQueueLast = newBaseQueueLast.next = _clone;
          } // Mark the event time of this update as relevant to this render pass.
          // TODO: This should ideally use the true event time of this update rather than
          // its priority which is a derived and not reverseable value.
          // TODO: We should skip this update if it was already committed but currently
          // we have no way of detecting the difference between a committed and suspended
          // update here.


          markRenderEventTimeAndConfig(updateExpirationTime, update.suspenseConfig); // Process this update.
*/
          // TODO: 判断计算函数是否有改变,有的话 重新计算值
          if (update.eagerReducer === reducer) {
            // If this update was processed eagerly, and its reducer matches the
            // current reducer, we can use the eagerly computed state.
            newState = update.eagerState;
          } else {
            var action = update.action;
            newState = reducer(newState, action);
          }
        }

        update = update.next;
      // TODO: update !== first 来判断队列是否结束
      } while (update !== null && update !== first);

      if (newBaseQueueLast === null) {
        newBaseState = newState;
      } else {
        newBaseQueueLast.next = newBaseQueueFirst;
      }

      // TODO: 判断是否相等来决定更新
      if (!objectIs(newState, hook.memoizedState)) {
      	// TODO: didReceiveUpdate = true
        markWorkInProgressReceivedUpdate();
      }

	  // TODO: 更新 新Fiber 上的 hook
      hook.memoizedState = newState;
      hook.baseState = newBaseState;
      hook.baseQueue = newBaseQueueLast;
      queue.lastRenderedState = newState;
    }

	// TODO: 这里没有重新bind,所以后面的 dispatch 绑定的还是最初始的 Fiber
    var dispatch = queue.dispatch;
    return [hook.memoizedState, dispatch];
  }

updateWorkInProgressHook

function updateWorkInProgressHook() {
    var nextCurrentHook;

	// TODO: (全局变量)保存本次渲染中当前的hook,第一个useState时该值为null,从 currentlyRenderingFiber$1.alternate 上获取,其余情况为上一次的hook
    if (currentHook === null) {
      // TODO: 从 新Fiber 的 alternate(指向 旧Fiber) 上拿到 hook 队列
      var current = currentlyRenderingFiber$1.alternate;

      if (current !== null) {
        nextCurrentHook = current.memoizedState;
      } else {
        nextCurrentHook = null;
      }
    } else {
      // TODO: 从第二个 useState 起开始根据 currentHook 拿当前hook
      nextCurrentHook = currentHook.next;
    }

    var nextWorkInProgressHook;

    if (workInProgressHook === null) {
      // TODO: workInProgressHook 在第一个useState时为null,从currentlyRenderingFiber$1.memoizedState (即 currentlyRenderingFiber$1 或 workInProgress 对应的 旧Fiber对象中取(之前 workInProgress.memoizedState 被清除了,所以拿到的也是null)
      nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState;
    } else {
      // TODO: workInProgressHook 从第二个 useState 起为最近渲染的 hook 的复制体,next 为 null
      nextWorkInProgressHook = workInProgressHook.next;
    }

    if (nextWorkInProgressHook !== null) {
      // TODO: 渲染函数中的 state更新 会在这里处理
      workInProgressHook = nextWorkInProgressHook;
      nextWorkInProgressHook = workInProgressHook.next;
      currentHook = nextCurrentHook;
    } else {
      // Clone from the current hook.
      // TODO: 如果 nextCurrentHook 为 null,说明 旧的hook 已经更新完了
      if (!(nextCurrentHook !== null)) {
        {
          throw Error( "Rendered more hooks than during the previous render." );
        }
      }

      currentHook = nextCurrentHook;
      // TODO: 创建一个新的 hook
      var newHook = {
        memoizedState: currentHook.memoizedState,
        baseState: currentHook.baseState,
        baseQueue: currentHook.baseQueue,
        queue: currentHook.queue,
        next: null
      };

      if (workInProgressHook === null) {
        // TODO: 第一个 useState 时 workInProgressHook 为 null ,把最新的 hook 复制体 赋值给 currentlyRenderingFiber$1.memoizedState, 更新 当前渲染中的 Fiber 的 memoizedState
        currentlyRenderingFiber$1.memoizedState = workInProgressHook = newHook;
      } else {
        // TODO: 后面的更新都 append 到 新Fiber 的 memoizedState
        workInProgressHook = workInProgressHook.next = newHook;
      }
    }

    return workInProgressHook;
  }

HooksDispatcherOnMount

const HooksDispatcherOnMount: Dispatcher = {
  readContext,

  useCallback: mountCallback,
  useContext: readContext,
  useEffect: mountEffect,
  useImperativeHandle: mountImperativeHandle,
  useLayoutEffect: mountLayoutEffect,
  useMemo: mountMemo,
  useReducer: mountReducer,
  useRef: mountRef,
  useState: mountState,
  useDebugValue: mountDebugValue,
  useResponder: createResponderListener,
};

HooksDispatcherOnMountInDEV

useState(initialState) {
/*
      currentHookNameInDev = 'useState';
      mountHookTypesDev();
      const prevDispatcher = ReactCurrentDispatcher.current;
      ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
      try {
      */
        return mountState(initialState);
        /*
      } finally {
        ReactCurrentDispatcher.current = prevDispatcher;
      }
      */
    },

rerenderState

function rerenderState(initialState) {
  return rerenderReducer(basicStateReducer);
}

rerenderReducer

// TODO: 相较于 updateReducer 更简单,不会去判断 优先级 和 过期时间
function rerenderReducer(reducer, initialArg, init) {
    var hook = updateWorkInProgressHook();
    var queue = hook.queue;

    if (!(queue !== null)) {
      {
        throw Error( "Should have a queue. This is likely a bug in React. Please file an issue." );
      }
    }

    queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous
    // work-in-progress hook.

    var dispatch = queue.dispatch;
    var lastRenderPhaseUpdate = queue.pending;
    var newState = hook.memoizedState;

    if (lastRenderPhaseUpdate !== null) {
      // The queue doesn't persist past this render pass.
      queue.pending = null;
      var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next;
      var update = firstRenderPhaseUpdate;

      do {
        // Process this render phase update. We don't have to check the
        // priority because it will always be the same as the current
        // render's.
        var action = update.action;
        newState = reducer(newState, action);
        update = update.next;
      } while (update !== firstRenderPhaseUpdate); // Mark that the fiber performed work, but only if the new state is
      // different from the current state.


      if (!objectIs(newState, hook.memoizedState)) {
        markWorkInProgressReceivedUpdate();
      }

      hook.memoizedState = newState; // Don't persist the state accumulated from the render phase updates to
      // the base state unless the queue is empty.
      // TODO: Not sure if this is the desired semantics, but it's what we
      // do for gDSFP. I can't remember why.

      if (hook.baseQueue === null) {
        hook.baseState = newState;
      }

      queue.lastRenderedState = newState;
    }

    return [newState, dispatch];
  }

useState

function useState(initialState) {
  var dispatcher = resolveDispatcher();
  return dispatcher.useState(initialState);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值