第十章:useInsertionEffect源码解析

105 阅读1分钟

前言

useInsertionEffect使用方法和useEffect一致,但是使用场景很少,开发者几乎很少使用;
useInsertionEffect也是和生命周期相关的hook;
useInsertionEffect 是为 CSS-in-JS 库的作者特意打造的。除非你正在使用 CSS-in-JS 库并且需要注入样式,否则你应该使用 useEffect 或者 useLayoutEffect

源码解析

// setup它应该返回一个 清理函数(cleanup)
useLayoutEffect(setup, dependencies?)

mount阶段

按照常规流程,调用HooksDispatcherOnMountInDEV.useInsertionEffect的方法,前置check检查方法,核心方法mountInsertionEffect
首先调用mountWorkInProgressHook方法,创建hook对象

const hook = {
    memoizedState: null,
    baseState: null,
    baseQueue: null,
    queue: null,
    next: null
};
fiber.memoizedState = hook;
const Update = 0b00000000000000000000000100;
fiber.flags |= Update;

memoizedState上挂载hook对象,标记为Update
pushEffect(HasEffect | Insertion, create, undefined, nextDeps);

const Insertion = 0b0010;
const HasEffect = 0b0001;
const effect = {
    tag: tag,
    create: create,
    destroy: destroy,
    deps: deps,
    // Circular
    next: null
};
fiber.updateQueue = effect;

pushEffect方法函数作用是为了往fiber.updateQueue.lastEffec的环状链表上创建effct对象,和useEffect处理逻辑一致,唯一区别是tag的标记值;

在commitRoot阶段,还记得useLayoutEffect的destroy方法执行时机吧,

// 处理dom 
commitMutationEffects(root, finishedWork, lanes);

// commitMutationEffects
commitReconciliationEffects(finishedWork); // 真实dom操作
// useInsertionEffect destory
commitHookEffectListUnmount(Insertion | HasEffect, finishedWork, finishedWork.return);
// useInsertionEffect create
commitHookEffectListMount(Insertion | HasEffect, finishedWork);

commitHookEffectListUnmount处理逻辑,遍历fiber.updateQueueeffect对象

// flags 为第一个参数
if((effect.tag & flags) === flags){
    if(effect.destroy != undefined){
        effect.destroy();
    }
}

commitHookEffectListMount处理逻辑和commitHookEffectListUnmount一致,

effect.destroy = effect.create();

update阶段

调用HooksDispatcherOnMountInDEV.useInsertionEffect的方法,前置check检查方法,核心方法updateInsertionEffect
参考useEffectuseLayoutEffect更新方法;
只不过是flags和tag不同而已。

总结方法

useInsertionEffect中create和destroy执行时机都是在dom挂载之后,在useLayoutEffectdestory执行之后;
会执行的当前的fiber的destory方法,再执行create方法。