Wsh's blog Wsh's blog
首页
  • 基础知识
  • ArkUI
  • UIAbility
  • 组件通信方式
  • 前端缓存
  • React
  • typescript
  • javascript
  • flutter
  • node
  • webpack
web3D😉
宝库📰
  • 分类
  • 标签
  • 归档
龙哥的大🐂之路 (opens new window)
GitHub (opens new window)

wsh

热爱前端的程序媛
首页
  • 基础知识
  • ArkUI
  • UIAbility
  • 组件通信方式
  • 前端缓存
  • React
  • typescript
  • javascript
  • flutter
  • node
  • webpack
web3D😉
宝库📰
  • 分类
  • 标签
  • 归档
龙哥的大🐂之路 (opens new window)
GitHub (opens new window)
  • react基础

  • react更新特性

  • react进阶

    • react 架构演变
    • react render阶段
    • react commit阶段
    • react diff
    • react 状态更新
    • react hook
      • Concurrent Mode
    • react
    • react进阶
    2022-04-22
    目录

    react hook

    # 01. hooks demo

          let workInProgressHook;
          let isMount = true;
    
          const fiber = {
            memoizedState: null,
            stateNode: App,
          };
          function run() {
            workInProgressHook = fiber.memoizedState;
            const app = fiber.stateNode();
            isMount = false;
            return app;
          }
          function dispatchAction(queue, action) {
            const update = {
              action,
              next: null,
            };
            console.log(queue, "update1");
            if (queue.pending === null) {
              update.next = update;
              console.log(update, "update2");
            } else {
              // 3 -> 0 -> 1 -> 2 -> 3
              // 4 -> 0 -> 1 -> 2 -> 3 -> 4
              // queue.pending 指向最后一个update,queue.pending.next 指向第一个update
              update.next = queue.pending.next; // 4 -> 0
              queue.pending.next = update; // 3 -> 4
            }
            queue.pending = update; // 当前最后一个指针指向update
    
            run();
          }
          function useState(initialState) {
            let hook;
            if (isMount) {
              hook = {
                queue: {
                  pending: null,
                },
                memoizedState: initialState,
                next: null,
              };
              if (!fiber.memoizedState) {
                fiber.memoizedState = hook;
              } else {
                workInProgressHook.next = hook;
              }
              workInProgressHook = hook;
            } else {
              hook = workInProgressHook;
              workInProgressHook = workInProgressHook.next;
            }
    
            let baseState = hook.memoizedState;
    
            if (hook.queue.pending) {
              let firstUpdate = hook.queue.pending.next;
    
              do {
                const action = firstUpdate.action;
                baseState = action(baseState);
                firstUpdate = firstUpdate.next;
              } while (firstUpdate !== hook.queue.pending);
    
              hook.queue.pending = null;
            }
            hook.memoizedState = baseState;
            return [baseState, dispatchAction.bind(null, hook.queue)];
          }
          function App() {
            const [num, updateNum] = useState(0);
            console.log(`${isMount ? "mount" : "update"} num: `, num);
            return {
              click() {
                updateNum((num) => num + 1);
              },
            };
          }
          window.app = run();
    
    

    # 02. hooks区分

    mount/update下的hooks来源于不同的对象,这类对象称之为: dispatcher

    mount时:

    const HooksDispatcherOnMount: Dispatcher = {
      readContext,
    
      useCallback: mountCallback,
      useContext: readContext,
      useEffect: mountEffect,
      useImperativeHandle: mountImperativeHandle,
      useLayoutEffect: mountLayoutEffect,
      useInsertionEffect: mountInsertionEffect,
      useMemo: mountMemo,
      useReducer: mountReducer,
      useRef: mountRef,
      useState: mountState,
      useDebugValue: mountDebugValue,
      useDeferredValue: mountDeferredValue,
      useTransition: mountTransition,
      useMutableSource: mountMutableSource,
      useSyncExternalStore: mountSyncExternalStore,
      useId: mountId,
    
      unstable_isNewReconciler: enableNewReconciler,
    };
    

    update时:

    const HooksDispatcherOnUpdate: Dispatcher = {
      readContext,
    
      useCallback: updateCallback,
      useContext: readContext,
      useEffect: updateEffect,
      useImperativeHandle: updateImperativeHandle,
      useInsertionEffect: updateInsertionEffect,
      useLayoutEffect: updateLayoutEffect,
      useMemo: updateMemo,
      useReducer: updateReducer,
      useRef: updateRef,
      useState: updateState,
      useDebugValue: updateDebugValue,
      useDeferredValue: updateDeferredValue,
      useTransition: updateTransition,
      useMutableSource: updateMutableSource,
      useSyncExternalStore: updateSyncExternalStore,
      useId: updateId,
    
      unstable_isNewReconciler: enableNewReconciler,
    };
    

    在mount/update调用的hook是不同的函数。 将不同情况对应的dispatcher赋值给全局变量ReactCurrentDispatcher的current属性。

        ReactCurrentDispatcher.current =
          current === null || current.memoizedState === null
            ? HooksDispatcherOnMount
            : HooksDispatcherOnUpdate;
    

    # 03. hook的数据结构

    const hook: Hook = {
      memoizedState: null,
    
      baseState: null,
      baseQueue: null,
      queue: null,
    
      next: null
    }
    

    注意

    hook.memoizedState: Hooks链表中保存的单一hook对应的数据

    fiber.memoizedState: FunctionComponent 对应fiber保存的Hooks链表

    # 04. hooks的调用顺序

    当初始化useState的时候,hooks是通过next来绑定state的顺序的,如果在多次调用hooks时,将其中一个useState有条件的省略,不执行,那么.next的时候,获得的state就不是对应的state,会造成state错位。

    # 05. memoizedState

    不同类型保存的memoizedState数据格式不一致

    • useState: 对于const [value, setValue] = useState(initialState),memoizedState保存value的值
    • useReducer: 对于const [state, dispatch]= useReducer(reducer, {}),memoized 保存state的值。
    • useEffect:memoizedState保存useEffect 回调函数,依赖项等的链表结构effect,effect链表同时会保存在fiber.updateQueue中。
    • useMemo: 对于useMemo(callback, [depA]), memoizedState保存(callback, [depA])
    • useCallback: 对于useCallback(callback, [depA]),memoizedState保存(callback, [depA]),与useMemo不同的是,useCallback保存的是callback函数本身,useMemo保存的是callback返回的结果
    • useRef: useRef(1), memoizedState保存{current: 1}

    没有memoizedState:

    • useContext

    # 06. useState/useReducer

    useReducer是useState的替代方案,会接收一个 (state, action) => newState的reducer,并返回当前的state以及配套的dispatch hook的工作流程主要分为:声明阶段和调用阶段。

    • 声明阶段就是在所在函数调用时,依次执行useReducer 和useState方法
    • 调用阶段即点即按钮后,dispatch或setValue被调用时。

    # 07. 声明阶段

    render阶段beginwork -> renderWithHooks 方法

    function useState(initialState) {
      var dispatcher = resolveDispatcher();
      return dispatch.useState(initialState);
    }
    
    function useReducer(reducer, initialArg, init) {
      var dispater = resolveDispatcher();
      var dispatcher.useReducer(reducer, initialArg, init);
    }
    

    dispater 在·不同场景下同一个hook会调用不同的函数

    # 08. mountState/mountReducer

    function mountState<S>(
      initialState:(()=>S) | S,
    ):[S, Dispatch<BasicStateAction<S>>] {
      // 创建并返回当前hook
      const hook = mountWorkInProgress();
    
      // 赋值初始state
      if (typeof initialState === 'function') {
        initialState = initialState();
      }
      hook.memoizedState = hook.baseState = initialState;
      const queue: UpdateQueue<S, BasicStateAction<S>> = {
        pending: null,
        interleaved: null,
        lanes: NoLanes,
        dispatch: null,
        lastRenderedReducer: basicStateReducer,
        lastRenderedState: (initialState: any),
      };
    
      // 创建queue
      const queue = (hook.queue = {
        pending: null,
        dispatch: null,
        lastRenderedReducer: basicStateReducer,
        lastRenderedState: (initialState: any)
      })
    
      // 创建dispatch
    
      const dispatch: Dispatch<
        BasicStateAction<S>,
      > = (queue.dispatch = (dispatchSetState.bind(
        null,
        currentlyRenderingFiber,
        queue,
      ): any));
    
      return [hook.memoizedState, dispatch];
    }
    

    queue的数据结构如下:

    const queue = (hook.queue = {
      pending: null, // 保存update 对象
      dispatch: null, // 保存dispatchAction.bind()的值
      lastRenderedReducer: reducer, // 上一次render时使用的ruducer
      lastRenderedState: (initialState: any)
    })
    

    useReducer的lastRenderedReducer为传入的reducer参数。 useState的lastRenderedReducer为basicStateReducer

    function basicStateReducer<S>(state: S, action: BasicStateAction<S>): S
      return typeof action === 'function' ? action(state) : action;
    

    useState的reducer参数为basicStateReducer的useReducer

    # 两种更新方式

    根据action 类型来区分是直接更新还是函数式更新。

    // 直接更新
    // 适用于与返回的新值与旧值不存在依赖关系
    useCount(newState)
    
    //函数式更新。
    // preState总能拿到上一次更新成功之后的最新状态
    // 如果正常使用,这两种方式没啥区别,但是如果是异步更新的话,他们之间的差别就会体现出来了.
    // 这是因为使用函数更新的时候,useCount函数将会被放在一个任务队列中,每一个useCount函数都可以拿到上一次更新成功后状态值。
    useCount((preState)=>{return nextState})
    
    

    # useState 与 setState 区别

    • 参数不同
    setState(updater,[,callback])
    updater:(object/function) -用于更新数据。
    callback:function-用于获取更新后的state的值。
    
    useState(initState)
    const [state,setState] =useState(initState)
    state 代表状态,
    setState()
    initState是初始状态值。
    
    • setState会自动浅合并,而useState不会。
    this.setState({  age:10; }) => this.setState({  ...this.state })
    

    # updateReducer

    在update时,useState与useReducer调用的是同一个函数updateReducer

    function updateReducer<S, I, A> (
      reducer: (S, A) => S,
      initialArg: I,
      init?: I => S
    ): [S, Dispatch<A>]{
      // 获取当前hook
      const hook = updateWorkInProgressHook();
    
      const queue = hook.queue;
    
      queue.lastRenderedReducer = reducer;
    
      const current: Hook = (currentHook: any);
      let baseQueue = current.baseQueue;
      const pendingQueue = queue.pending;
    
      // 同update与updateQueue 类似的更新逻辑
      if (pendingQueue !== null) {
        if (baseQueue !== null) {
          // 合并待处理队列和基本队列。
          const baseFirst = baseQueue.next;
          const pendingFirst = pendingQueue.next;
          baseQueue.next = pendingFirst;
          pendingQueue.next = baseFirst;
        }
        current.baseQueue = baseQueue = pendingQueue;
        queue.pending = null;
      }
      // ...
    
    
      const dispatch: Dispatch<A> = (queue.dispatch: any);
      return [hook.memoizedState, dispatch];
    }
    

    流程概括为: 找到对应的hook,根据update计算该hook的state 并返回

    mount与update 获取当前hook方式不一样,mountWorkInProgressHook/updateWorkInProgressHook

    1. mount是调用ReactDOm.render或初始化API产生的更新,只会执行一次
    2. update触发更新行为有多种,可能是在事件回调或者副作用触发,又或者是render阶段触发的更新,为了避免组件无限循环更新,需要区别对待

    render 假设调用setValue触发更新,不做限制,这次更行会开启一次新的render阶段,导致无限循环。 所以react 用标记变量 didScheduleRenderPhaseUpdate 判断是否是render阶段触发的更新。

    # 调用阶段

    调用阶段会执行dispatchAction, 整个过程:创建update,将update加入queue.pending中国,并开启调度

    function dispatchAction(fiber, queue, action) {
      
      // ... 创建update
      var update = {
        eventTime: eventTime,
        lane: lane,
        suspenseConfig: suspenseConfig,
        action: action,
        eagerReducer: null,
        eagerState: null,
        next: null
      }
    
      // ... 将update加入queue.pending
    
      var alternate = fiber.alternate;
    
      if(fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1) {
        // render阶段触发的更新
        didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;
      } else {
        if (fiber.lanes === NOLanes && (alternate === null || alternate.lanes === NoLanes)) {
          // ...fiber的updateQueue为空, 优化路径
        }
        sscheduleUpdateOnFiber(fiber, lane, eventTime);
      }
    }
    
    if(fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1) {
    

    currentlyRenderingFiber 即 workInProgress, workInProgress 代表当前处于render阶段 触发更新时通过bind预先保存的fiber与workInProgress全等,代表本次更新发生于FunctionComponent 对应fiber 的render阶段。

    if (fiber.lanes === NOLanes && (alternate === null || alternate.lanes === NoLanes)) {
    

    fiber.lanes 保存fiber上存在的update优先级 fiber.lanes === NOLanes 代表不存在update

    useState整体流程:

    # 09. useEffect

    在React中类似像componentDidMount这样的生命周期方法中,因为可能会执行setState这样的方法而产生新的更新,我们称之为side effect即副作用。

    本身FunctionComponent因为是pure function,所以不会产生任何的副作用,而useEffect和useLayoutEffect是带给FunctionComponent产生副作用能力的Hooks,他们的行为非常类似componentDidMount和componentDidUpdate

    他们接受一个方法作为参数,该方法会在每次渲染完成之后被调用;其次还接受第二个参数,是一个数组,这个数组里的每一个内容都会被用来进行渲染前后的对比,如果没有变化,则不会调用该副作用。

    # useEffect 执行顺序

    React 中 effect hook 的定义

    useEffect(didUpdate);
    useEffect(didUpdate, dependencies);
    
    • 用途:effect hook 用于完成副作用操作

    • 参数:

      • didUpdate 参数接收一个包含命令式、且可能有副作用代码的函数。
      • dependencies 参数接收一个数组,数组中的元素表示 effect 所依赖的值。
    • 执行时机:

      • 默认情况:didUpdate 会在每轮组件渲染完成后执行。
      • 条件执行:当传入 dependencies 参数时,didUpdate 仅在依赖值发生变化时执行
    • 清除:

      • didUpdate 函数可以返回一个清除函数以清除副作用操作(如取消订阅、清除定时器等)。如果组件多次渲染,则上一个 effect 会在下一个 effect 执行之前被清除。

    不同组件之间执行顺讯如下:

    • 组件渲染后,执行effect的顺序,组件树的后序深度优先遍历。
    • 组件重新渲染时,清除 effect 的顺序:组件树的后序深度优先遍历。
    • 组件unmount时,清除effect的顺序,组件树的前序深度优选遍历。

    # flushPassiveEffectsImpl

    flushPassiveEffects: 触发useEffect回调与其他同步任务。内部会设置优先级,并执行flushPassiveEffectsImpl

    flushPassiveEffectImpl主要做三件事

    • 调用该useEffect在上一次render时的销毁函数
    • 调用该useEffect在本次render时的回调函数
    • 如果存在同步任务,不需要等待下次事件循环的宏任务,提前执行

    # 阶段一

    useEffect的执行需要保证所有组件useEffect的销毁函数必须都执行完称才能执行任意一个组件的useEffect的回调函数。(因为多个组件可能共用一个ref)

    如果不是按照 全部销毁 再 全部执行 的顺序,那么在某个组件useEffect的销毁函数中修改的ref.current可能影响另外一个组件useEffect的回调函数中的同一个ref的current属性。

    在阶段一会遍历并执行所有useEffect的销毁函数,pendingPassiveHookEffectsUnmount中保存了所有需要执行销毁的useEffect

    const unmountEffects = pendingPassiveHookEffectsUnmount;
    pendingPassiveHookEffectsUnmount = [];
    
    // pendingPassiveHookEffectsUnmount数组索引【i】保存需要销毁的effect,i+1保存该effect对应的fiber
    for (let i = 0; i < unmountEffects; i +=2) {
      const effect = ((unmountEffects[i]: any) : HookEffect);
      const fiber = ((unmountEffects[i+1]: any): Fiber);
    
      const destory = effect.destory;
      effect.destory = undefined;
      
      if (typeof destory === 'function') {
         // 销毁函数存在则执行
        try {
         destory();
        } catch {
          captureCommitPhaseError(fiber, error);
        }
      }
    }
    
    

    pendingPassiveHookEffectsUnmount push effect在layout阶段commitLayoutEffectOnFiber内的 schedulePassiveEffects方法

    function schedulePassiveEffects(finishedWork: Fiber) {
      const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);
      const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
      if (lastEffect !== null) {
        const firstEffect = lastEffect.next;
        let effect = firstEffect;
        do {
          const {next, tag} = effect;
          if (
            (tag & HookPassive) !== NoHookEffect &&
            (tag & HookHasEffect) !== NoHookEffect
          ) {
            // 向`pendingPassiveHookEffectsUnmount`数组内`push`要销毁的effect
            enqueuePendingPassiveHookEffectUnmount(finishedWork, effect);
            // 向`pendingPassiveHookEffectsMount`数组内`push`要执行回调的effect
            enqueuePendingPassiveHookEffectMount(finishedWork, effect);
          }
          effect = next;
        } while (effect !== firstEffect);
      }
    }
    

    # 阶段二

    与阶段一类似,同样时遍历数组,执行对应effect的回调函数,enqueuePendingPassiveHookEffectMount 同样也在scheduPassiveEffects中, enqueuePassiveHookEffectsMount 保存了所有需要执行回调的useEffect

    const mountEffects = pendingPassiveHookEffectsMount;
    pendingPassiveHookEffectsMount = [];
    for (let i = 0; i < mountEffects.length; i += 2) {
      const effect = ((mountEffects[i]: any): HookEffect);
      const fiber = ((mountEffects[i + 1]: any): Fiber);
      
      try {
        const create = effect.create;
        effect.destroy = create();
      } catch (error) {
        captureCommitPhaseError(fiber, error);
      }
    }
    

    # 10. useRef

    作用:

    • 作用于Dom元素
    • 获取子组件的实例(只有类组件可用)
    • 在函数组件中的一个全局变量,不会因为重复 render 重复申明, 类似于类组件的 this.xxx

    在mount/ update 对应两个不同的dispatcher

    function mountRef<T>(initialValue: T): {| current: T|}{
      // 获取当前useRef hook
      cosnt hook = mountWorkInProgress();
      // 创建ref
      const ref = { current: initialValue};
      hook.memoizedState = ref;
    
      return ref;
    }
    
    function updateRef<T>(initialValue: T): {|current: T|} {
      // 获取当前useRef hook
      const hook = updateWorkInProgress();
      // 返回保存的数据
      return hook.memoizedState;
    }
    

    createRef实现:

    function createRef(): RefObject {
      const refObject = {
        current: null
      };
      return refObject;
    }
    

    functionComponent hooks 生命周期:

    # useRef 与createRef 区别

    • createRef 仅能用在classComponent,useRef仅能用在FunctionComponent
    • createRef 每次渲染都会返回一个新的引用,而 useRef 每次都会返回相同的引用。 createRef的值会随着 FunctionComponent 重复执行而不断被初始化 错误示例:永远也拿不到 ref
    function App() {
      const valueRef = React.createRef(); //随着App render 重复初始化
      return <div ref={valueRef} />;
    }
    
    const Text = () => {
        const [renderIndex, setRenderIndex] = useState(0);
        const refFromUseRef = useRef();
        const refFromCreateRef = createRef();
        if (!refFromUseRef.current) {
            refFromUseRef.current = renderIndex;
        }
        if (!refFromCreateRef.current) {
            refFromCreateRef.current = renderIndex;
        }
        return <div>
            <p>renderIndex: {renderIndex}</p>
            <p>
                <b>
                    refFromUseRef: {refFromUseRef.current}
                </b>
                <b>
                    refFromCreateRef: {refFromCreateRef.current}
                </b>
            </p>
            <p>
                <button onClick={() => setRenderIndex(prevIndex => prevIndex+1)}>点击</button>
            </p>
        </div>;
    };
    

    # useRef与全局变量的区别

    在组件外部声明和使用'let'变量不会触发re-rendering组件,与使用useRef相同,后者也不会触发re-rendering,那二者有什么不同?

    • useRef 是定义在实例基础上的,如果代码中有多个相同的组件,每个组件的 ref 只跟组件本身有关,跟其他组件的 ref 没有关系。
    • 组件前定义的 global 变量,是属于全局的。如果代码中有多个相同的组件,那这个 global 变量在全局是同一个,他们会互相影响。

    # ref的工作流程

    HostComponent,classComponent,forwardRef 赋值ref属性

    • HostComponent
    <div ref={domRef}></div>
    
    • classComponent/forwardRef
    <App ref={cnRef}/>
    

    其中forwardRef 将ref作为第二参数进行传递,不会进入ref的工作流程。

    // secondArg 为传递下去的ref
    let children = Component(props, secondArg)
    

    ref的更新在mutation阶段。 mutation执行DOM的依据是effectTag, 所以Ref更新也会赋值对应的effectTag

    ref的工作流程分为两步

    • render阶段为含有ref属性的fiber 添加Ref effectTag
    • commit 阶段为包含Ref effectTag的fiber执行对应的更新

    # 阶段一

    在render阶段 beginWork与completeWork中 markRef方法为含有ref属性的fiber增加Ref effectTag

    // beginWork的markRef
    function markRef(current: Fiber | null, workInProgress: Fiber) {
      const ref = workInProgress.ref;
      if (
        (current === null && ref !== null) ||
        (current !== null && current.ref !== ref)
      ) {
        // Schedule a Ref effect
        workInProgress.effectTag |= Ref;
      }
    }
    // completeWork的markRef
    function markRef(workInProgress: Fiber) {
      workInProgress.effectTag |= Ref;
    }
    

    组件对应fiber被赋值Ref effectTag需要满足的条件:

    • mount时,workInProgress.ref !== null,即存在ref属性
    • update时,current.ref !== ref ref属性改变

    # 阶段二

    • 针对属性改变的,需要先移除之前的ref
    function commitMutationEffects(root: FiberRoot, renderPriorityLevel) {
      while (nextEffect !== null) {
        const effectTag = nextEffect.effectTag;
        if (effectTag & Ref) {
          const current = nextEffect.alternate;
          if (current !== null) {
            // 移除之前的ref
            commitDetachRef(current);
          }
        }
      }
    }
    
    function commitDetachRef(current: Fiber) {
      const currentRef = current.ref;
      if (currentRef!== null) {
        if (typeof currentRef === 'function') {
          currentRef(null);
        } else {
          currentRef.current = null;
        }
      }
    
    }
    
    • ref 赋值(commitLayoutEffect 执行 commitAttachRef)
    function commitAttachRef(finishedWork: Fiber) {
       const ref = finishedWork.ref;
       if (ref !== null) {
        // 获取ref属性对应的Component实例
        const instance = finishedWork.stateNode;
        let instanceToUse;
        switch (finishedWork.tag) {
          case HostComponent:
            instanceToUse = getPublicInstance(instance);
            break;
          default:
            instanceToUse = instance;
        }
        // 赋值ref
        if (typeof ref === 'function') {
          ref(instanceToUse);
        } else {
          ref.current = instanceToUse;
        }
      }
    }
    

    # 11. useCallback/useMemo

    const memoizedCallback = useCallback(() => {
      do(depA, depB)
    }, [depA, depB])
    // 返回一个 memoized 回调函数 。
    const memoizedValue = useMemo(() => {
      computeValue(depA, depB)
    }, [depA, depV])
    // 返回一个 memoized 值 。
    
    useCallback(fn, deps) 类似于 useMemeo(()=> fn,deps)
    

    # mount

    function mountMemo<T> (
      nextCreate: () => T,
      deps: Array<mixed> | void | null
    ) : T {
      // 创建并返回当前hook
      const hook = mountWorkInProgress();
      const nextDeps = deps === undefined ? null : deps;
    
      // 计算value
      const nextValue = nextCreate();
    
      // 将value与deps保存在hook.memeoized
      hook.memoizedState = [nextValue, nextDeps];
    
      return nextValue;
    }
    
    function mountCallback<T>(callback: T, deps: Array<mixed> | void | null) : T {
      // 创建并返回hook
      const hook = mountWorkInProgress();
      const nextDeps = deps === undefined ? null : deps;
    
      // 将value与deps保存在hook.memoizedState中
      hook.memoizedState = [callback,deps];
      return callback
    }
    

    # update

    function updateMemo<T> (
      nextCreate: () => T,
      deps: Array<mixed> | void | null
    ){
      // 返回当前的hook
      const hook = updateWorkInProgress();
      const nextDeps = deps === undefined ? null : deps;
      const prevState = hook.memoizedState;
    
      if (prevState !== null) {
        if (nextDeps !== null) {
          const prevDeps: Array<mixed> | null = prevState[1];
          // 判断update前后value是否变化
          if(areHookInputsEquql(nextDeps. prevDeps)) {
             // 未变化
            return prevState[0];
          }
        }
      }
      // 变化。 需要重新计算
      const nextValue = nextCreate();
      hook.memoizedState = [nextValue, nextDeps];
      return nextValue;
    }
    
    function updateCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
      // 返回当前hook
      const hook = updateWorkInProgressHook();
      const nextDeps = deps === undefined ? null : deps;
      const prevState = hook.memoizedState;
    
      if (prevState !== null) {
        if (nextDeps !== null) {
          const prevDeps: Array<mixed> | null = prevState[1];
          // 判断update前后value是否变化
          if (areHookInputsEqual(nextDeps, prevDeps)) {
            // 未变化
            return prevState[0];
          }
        }
      }
    
      // 变化,将新的callback作为value
      hook.memoizedState = [callback, nextDeps];
      return callback;
    }
    

    二者区别value是回调函数本身还是回调函数的执行结果。

    #react
    react 状态更新
    Concurrent Mode

    ← react 状态更新 Concurrent Mode→

    最近更新
    01
    组件通信方式
    01-07
    02
    UIAbility
    01-07
    03
    ATKTS
    01-06
    更多文章>
    Theme by Vdoing | Copyright © 2022-2025 Wsh | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式