Skip to content
On this page

参照上一节流程,同样分成创建(mount)和更新(update)过程

useEffect

mount

js
function mountEffect(create, deps) {
	return mountEffectImpl(
		UpdateEffect | PassiveEffect,
		HookPassive,
		create,
		deps,
	);
}

function mountEffectImpl(fiberFlags, hookFlags, create, deps) {
  const hook = mountWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps; // 依赖项
  currentlyRenderingFiber.flags |= fiberFlags; // 设置flags
  // 保存的是最后一个 effect
  hook.memoizedState = pushEffect(
    HookHasEffect | hookFlags,
    create,
    undefined,
    nextDeps,
  );
}

function pushEffect(tag, create, destroy, deps) {
	// 创建effect对象
  const effect: Effect = {
    tag,
    create,
    destroy,
    deps,
    next: (null: any),
  };
  let componentUpdateQueue = (currentlyRenderingFiber.updateQueue);
  // 建立 环状链表
  if (componentUpdateQueue === null) {
	  // 创建 updateQueue保存effect
    componentUpdateQueue = createFunctionComponentUpdateQueue();
    currentlyRenderingFiber.updateQueue = componentUpdateQueue;
    componentUpdateQueue.lastEffect = effect.next = effect;
  } else {
    const lastEffect = componentUpdateQueue.lastEffect;
    if (lastEffect === null) {
      componentUpdateQueue.lastEffect = effect.next = effect;
    } else {
      const firstEffect = lastEffect.next;
      lastEffect.next = effect;
      effect.next = firstEffect;
      componentUpdateQueue.lastEffect = effect;
    }
  }
  return effect;
}

update

js
function updateEffectImpl(fiberFlags, hookFlags, create, deps) {
	const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  let destroy = undefined;

  if (currentHook !== null) {
	  // 保存的最后一个effect
    const prevEffect = currentHook.memoizedState; 
     // effect的销毁函数
     // 需要等到 currentHook 的 create 函数执行返回才有 destroy
    destroy = prevEffect.destroy;
    if (nextDeps !== null) {
	    // 有依赖项
      const prevDeps = prevEffect.deps;
      if (areHookInputsEqual(nextDeps, prevDeps)) {
	      // 依赖项的值没有改变
	      // 没有变化也要push,保证 wip.memoizedState保存的单向链表顺序正确
        pushEffect(hookFlags, create, destroy, nextDeps);
        return;
      }
    }
  }
  // 依赖项 有改变
  currentlyRenderingFiber.flags |= fiberFlags;
	// 记录新的 effect
  hook.memoizedState = pushEffect(
    HookHasEffect | hookFlags, 
    // 只有包含 HookHasEffect 的flag,才会在本次commit 阶段执行
    create,
    destroy,
    nextDeps,
  );
}

useLayoutEffect

js
function mountLayoutEffect(
	create: () => (() => void) | void,
	deps: Array<mixed> | void | null,
): void {
	return mountEffectImpl(UpdateEffect, HookLayout, create, deps);
}

function updateLayoutEffect(
	create: () => (() => void) | void,
	deps: Array<mixed> | void | null,
): void {
	return updateEffectImpl(UpdateEffect, HookLayout, create, deps);
}

相比 useEffect 只是传入的 flag 不同,导致 effect 内部的调用函数不同

流程总结

commitRoot -> beforeCommitMutation 包含 schedule(调度异步更新) -> mutation(实行更新) 包含 layoutEffect 的 destroy函数(mount时为空) -> layout 触发 layoutEffect 的create 同时赋值 destroy -> 回调useEffect 的 destroy 和 create