55.React学习笔记.hook 原理浅析

在讲hook原理之前,我们需要先简单了解一下Fiber。

一.Fiber

React16推出的,用于提高当前浏览器显示界面性能的东西,减少卡顿等待。

我们电脑屏幕都有一个刷新率(Hz),电脑屏幕上的东西,CPU提供数据,GPU将其绘制出来;
电脑屏幕按固定的频率,从缓存中取出(帧)并显示;缓存防止屏幕出现撕裂 ;
浏览器刷新频率一般与电脑一致,浏览器根据电脑传来的vsync(同步信号)来刷新。

  1. GUI渲染和JS代码执行(还有用户事件响应,键盘事件响应,requestAnimationFrame(),layout,paint)是在同一个线程的,互斥,最好在一帧中将所有操作做完。若一直执行JS代码,那GUI就一直得不到渲染,然后就会保持上一帧的图像。耗费时间长,也就意味着明显的卡顿;
  2. 早期React中,点击按钮后,有大量组件生成或更新,会大量占用浏览器刷新时间;这些耗时操作,都是在上一步中,且在一帧时间内,JS线程完成后才执行的;
  3. 为了解决上述问题, 现在React把我们需要reconciliation协同的东西(diff,更新),切分成很多的Fiber
  4. Fiber为执行单元(执行碎片)。Fiber形成一个Fiber树,与ReactElement树结构一一对应;
  5. 现在控制权交给浏览器,让浏览器先做一些必须执行的用户/键盘/js代码响应等,若有剩余时间再做requestIdleCallback()=>Fiber碎片)来执行Fiber碎片。
    Fiber源码去react-reconciler中,东西太多,先打个标记,在开发过程如果有需求再做深入。

二.useState Hook原理

现在举个useState Hook的例子。


image.png
  1. useState的本质是dispatcher.useState(initialState)
    ,也就是resolveDispatcher();
image.png
  1. resolveDispatch方法返回的dispatcher来自于ReactCurrentDispatcher.current。
image.png
  1. ReactCurrentDispatcher中的Dispatcher又来自于'react-reconciler/src/ReactFiberHooks'中。
  1. 具体Dispatcher如下:
export type Dispatcher = {|
  readContext(
    context: ReactContext,
    observedBits: void | number | boolean,
  ): T,
  useState(initialState: (() => S) | S): [S, Dispatch>],
  useReducer(
    reducer: (S, A) => S,
    initialArg: I,
    init?: (I) => S,
  ): [S, Dispatch],
  useContext(
    context: ReactContext,
    observedBits: void | number | boolean,
  ): T,
  useRef(initialValue: T): {|current: T|},
  useEffect(
    create: () => (() => void) | void,
    deps: Array | void | null,
  ): void,
  useLayoutEffect(
    create: () => (() => void) | void,
    deps: Array | void | null,
  ): void,
  useCallback(callback: T, deps: Array | void | null): T,
  useMemo(nextCreate: () => T, deps: Array | void | null): T,
  useImperativeHandle(
    ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,
    create: () => T,
    deps: Array | void | null,
  ): void,
  useDebugValue(value: T, formatterFn: ?(value: T) => mixed): void,
  useResponder(
    responder: ReactEventResponder,
    props: Object,
  ): ReactEventResponderListener,
  useDeferredValue(value: T, config: TimeoutConfig | void | null): T,
  useTransition(
    config: SuspenseConfig | void | null,
  ): [(() => void) => void, boolean],
|};
image.png

image.png
  1. 当组件使用了hooks进行渲染的时候,就会调用renderWithHooks函数。


    image.png
  • 真实环境下:如图所示,分为挂载时,和更新时的HooksDispatcher。
image.png

image.png
  1. 使用useState,第一次运行时,如上图所示。 若workInProgressHook为空则初始化,给它赋值hook。
image.png

image.png
  1. mountState函数中,若useState传入的为函数,多了一步执行过程。
    hook的memorizedState和baseState都为initialState。
    如果我调用多次useState,就如mountWorkInPrograssHook函数中的一样,判断workInProgressHook不为null,则创建一个新的hook,并将其拼接到workInProgressHook的next中。最终形成一个链表。
image.png
  1. 等到执行setState时,才会用到queue这个值。

  2. 在dispatchAction中 ,Fiber和queue的值,都来自刚刚mountState函数中的currentlyRenderingFiber和queue。

image.png

image.png

image.png
  1. 在执行setState时,就是进行一个dispatchAction的操作。
    其中创建了一个update,代表了本次要更新的东西,更新的东西存放在action中,然后再放到update中。
    若执行多次,则放入链表中。
image.png
  1. 在NoWork没有工作的状态下,useState本质上用的是useReducer;若有工作,在空闲的时候再执行update。

若有多个hook同时使用,本质上是以链表的形式,一个个保存hooks的。
不能在if中使用hook,因为其是个链表,可能数据会错乱。

东西太多了,可能看的有点乱,以后有需求再反复深入。

你可能感兴趣的:(55.React学习笔记.hook 原理浅析)