前言
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.updateQueue中effect对象
// flags 为第一个参数
if((effect.tag & flags) === flags){
if(effect.destroy != undefined){
effect.destroy();
}
}
commitHookEffectListMount处理逻辑和commitHookEffectListUnmount一致,
effect.destroy = effect.create();
update阶段
调用HooksDispatcherOnMountInDEV.useInsertionEffect的方法,前置check检查方法,核心方法updateInsertionEffect;
参考useEffect和useLayoutEffect更新方法;
只不过是flags和tag不同而已。
总结方法
useInsertionEffect中create和destroy执行时机都是在dom挂载之后,在useLayoutEffect的destory执行之后;
会执行的当前的fiber的destory方法,再执行create方法。