React源码解析(一) Fiber和Dispatcher

本文章中为了精简会删除一些不必要的属性和注释,react源码在这里,有需要的自己去拉一下:React源码

一.fiber

常见面试题(一)中曾说过Fiber可以看做是一种数据结构, Fiber把渲染更新过程拆分成多个子任务,每次只做一小部分,做完看是否还有剩余时间,如果有继续下一个任务;如果没有,挂起当前任务,将时间控制权交给主线程,等主线程不忙的时候在继续执行,即可以中断与恢复。今天就找来了关于Fiber的源码,废话少说先上源码

// A Fiber is work on a Component that needs to be done or was done. There can
// be more than one per component.
export type Fiber = {
  // Tag identifying the type of fiber.
  tag: WorkTag,

  // Unique identifier of this child.
  key: null | string,

  // The value of element.type which is used to preserve the identity during
  // reconciliation of this child.
  elementType: any,

  // The resolved function/class/ associated with this fiber.
  type: any,

  // The local state associated with this fiber.
  stateNode: any,
  
  // The Fiber to return to after finishing processing this one.
  // This is effectively the parent, but there can be multiple parents (two)
  // so this is only the parent of the thing we're currently processing.
  // It is conceptually the same as the return address of a stack frame.
  return: Fiber | null,

  // Singly Linked List Tree Structure.
  child: Fiber | null,
  sibling: Fiber | null,
  index: number,

  // The ref last used to attach this node.
  // I'll avoid adding an owner field for prod and model that as functions.
  ref:
    | null
    | (((handle: mixed) => void) & {_stringRef: ?string, ...})
    | RefObject,

  refCleanup: null | (() => void),

  // Input is the data coming into process this fiber. Arguments. Props.
  pendingProps: any, // This type will be more specific once we overload the tag.
  memoizedProps: any, // The props used to create the output.

  // A queue of state updates and callbacks.
  updateQueue: mixed,

  // The state used to create the output
  memoizedState: any,

  // Dependencies (contexts, events) for this fiber, if it has any
  dependencies: Dependencies | null,

  // Effect
  flags: Flags,
  subtreeFlags: Flags,
  deletions: Array<Fiber> | null,

  lanes: Lanes,
  childLanes: Lanes,

  // This is a pooled version of a Fiber. Every fiber that gets updated will
  // eventually have a pair. There are cases when we can clean up pairs to save
  // memory if we need to.
  alternate: Fiber | null,

};

  在开头中,也说了"fiber是一个需要完成或者已经完成的组件,它可以存在多个"。这也印证了开头所说的:

Fiber把渲染更新过程拆分成多个子任务,每次只做一小部分

  别看源码中fiber的属性有这么多,其实我们需要主要了解的就以下几个:tag用于标识 fiber 的类型,例如函数组件、类组件等。stateNode是Fiber关联的本地状态节点通常指向组件实例或指向实际的 DOM 节点。key用于在同级元素中唯一标识一个 fiber,以帮助 React 在更新时识别和复用元素。 return返回的是完成处理后的纤程,其指向父级 fiber,相当于调用栈中的返回地址。childsibling分别指向子 fiber 和兄弟 fiber,从此就可以形成一个单链表树结构。pendingPropsmemoizedProps分别表示待处理的属性和已处理的属性。updateQueue包含状态更新和回调的队列。
  了解完这几个属性再去深入了解fiber,就会发现容易理解很多

二.Dispatcher

  hooks相信大家都特别了解了,面对这么复杂的源码,我肯定第一时间先去挑个软柿子捏一捏,去找一下useState,然后当我去react-main/packages/react/src/ReactHooks.js找到useState的时候我有点懵。怎么回事?怎么返回的是dispactcher的useState?这个dispatcher又是什么来的?

//软柿子//
export function useState<S>(
  initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
  const dispatcher = resolveDispatcher();
  return dispatcher.useState(initialState);
}

  在然后顺着一步步找上去,找到了Dispatcher的源码,Dispatcher 是 React 内部用于管理 Hooks 的一个核心接口。它的主要作用是提供一组方法,用于管理和执行组件中的各种 Hook。这些方法允许 React 在组件的生命周期中管理状态、上下文、引用、副作用等。我们先来看一下源码:

//react-main/packages/react-reconciler/src/ReactInternalTypes.js
export type Dispatcher = {
  use: <T>(Usable<T>) => T,
  readContext<T>(context: ReactContext<T>): T,
  useState<S>(initialState: (() => S) | S): [S, Dispatch<BasicStateAction<S>>],
  useReducer<S, I, A>(
    reducer: (S, A) => S,
    initialArg: I,
    init?: (I) => S,
  ): [S, Dispatch<A>],
  useContext<T>(context: ReactContext<T>): T,
  useRef<T>(initialValue: T): {current: T},
  useEffect(
    create: (() => (() => void) | void) | (() => {...} | void | null),
    createDeps: Array<mixed> | void | null,
    update?: ((resource: {...} | void | null) => void) | void,
    updateDeps?: Array<mixed> | void | null,
    destroy?: ((resource: {...} | void | null) => void) | void,
  ): void,
  // TODO: Non-nullable once `enableUseEffectEventHook` is on everywhere.
  useEffectEvent?: <Args, F: (...Array<Args>) => mixed>(callback: F) => F,
  useInsertionEffect(
    create: () => (() => void) | void,
    deps: Array<mixed> | void | null,
  ): void,
  useLayoutEffect(
    create: () => (() => void) | void,
    deps: Array<mixed> | void | null,
  ): void,
  useCallback<T>(callback: T, deps: Array<mixed> | void | null): T,
  useMemo<T>(nextCreate: () => T, deps: Array<mixed> | void | null): T,
  useImperativeHandle<T>(
    ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
    create: () => T,
    deps: Array<mixed> | void | null,
  ): void,
  useDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void,
  useDeferredValue<T>(value: T, initialValue?: T): T,
  useTransition(): [
    boolean,
    (callback: () => void, options?: StartTransitionOptions) => void,
  ],
  useSyncExternalStore<T>(
    subscribe: (() => void) => () => void,
    getSnapshot: () => T,
    getServerSnapshot?: () => T,
  ): T,
  useId(): string,
  useCacheRefresh: () => <T>(?() => T, ?T) => void,
  useMemoCache: (size: number) => Array<any>,
  useHostTransitionStatus: () => TransitionStatus,
  useOptimistic: <S, A>(
    passthrough: S,
    reducer: ?(S, A) => S,
  ) => [S, (A) => void],
  useFormState: <S, P>(
    action: (Awaited<S>, P) => S,
    initialState: Awaited<S>,
    permalink?: string,
  ) => [Awaited<S>, (P) => void, boolean],
  useActionState: <S, P>(
    action: (Awaited<S>, P) => S,
    initialState: Awaited<S>,
    permalink?: string,
  ) => [Awaited<S>, (P) => void, boolean],
  // TODO: Non-nullable once `enableSwipeTransition` is on everywhere.
  useSwipeTransition?: <T>(
    previous: T,
    current: T,
    next: T,
  ) => [T, StartGesture],
};

  是不是觉得有点熟悉,为什么我们常见的hooks都在这里面?这就要说说Dispatcher是如何管理和执行其中的hooks的:

  1.首先Dispatcher是动态分配的,其具体实现在不同的渲染阶段会有所不同(例如在组件挂载时,Dispatcher 会被设置为 HooksDispatcherOnMount,在更新时会被设置为 HooksDispatcherOnUpdate),可以对比图中两个Dispatcher的不同,感兴趣的小伙伴可以去react-main\packages\react-reconciler\src\ReactFiberHooks.js这个文件下看一下
在这里插入图片描述

  2.在组件的渲染过程中,当调用 Hook(如 useState、useEffect 等)时,实际上是通过当前的 Dispatcher 实例来调用相应的方法。这些方法会根据当前的渲染阶段和组件状态(用于Dispathcher动态分配存在差异),执行相应的逻辑。

  3.每个 Hook 的调用都会在内部维护一个链表结构,用于存储 Hook 的状态和相关信息。Dispatcher 的实现会管理这些链表,确保在每次渲染时正确地更新和复用 Hook 的状态。

  4.对于副作用(如 useEffect),Dispatcher 会在渲染完成后调度这些副作用的执行。副作用的清理函数也会在适当的时候被调用,通常是在组件卸载或依赖项变化时。

  5.Dispatcher 通过记忆化技术(如 useMemo 和 useCallback)来减少不必要的计算和渲染。通过管理 Hook 的依赖项,Dispatcher 可以避免在依赖项未变化时重复执行相同的逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值