useLayoutEffect會在所有DOM變更之后同步調(diào)用effect冀宴。
執(zhí)行DOM變更時調(diào)用effect destroy()方法,DOM變更后同步調(diào)用effect create()方法略贮。
- main.jsx
function FunctionComponent() {
const [number, setNumber] = React.useState(0);
React.useEffect(() => {
console.log("useEffect1");
return () => {
console.log("destroy useEffect1");
};
});
React.useLayoutEffect(() => {
console.log("useLayoutEffect2");
return () => {
console.log("destroy useLayoutEffect2");
};
});
React.useEffect(() => {
console.log("useEffect3");
return () => {
console.log("destroy useEffect3");
};
});
React.useLayoutEffect(() => {
console.log("useLayoutEffect4");
return () => {
console.log("destroy useLayoutEffect4");
};
});
return <button onClick={() => setNumber(number + 1)}>{number}</button>;
}
let element = <FunctionComponent />;
const root = createRoot(document.getElementById("root"));
console.log("root", root);
root.render(element);
- ReactFiberCommitWork.js
export function commitMutationEffectsOnFiber(finishedWork, root) {
const { tag } = finishedWork;
const current = finishedWork.alternate;
const flags = finishedWork.flags;
switch (tag) {
case FunctionComponent:
recursivelyTraverseMutationEffects(root, finishedWork);
commitReconciliationEffects(finishedWork);
if (flags & Update) {
commitHookEffectListUnmount(HookHasEffect | HookLayout, finishedWork);
}
break;
...
}
}
export function commitLayoutEffects(finishedWork, root) {
const current = finishedWork.alternate;
commitLayoutEffectOnFiber(root, current, finishedWork);
}
function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork) {
const flags = finishedWork.flags;
switch (finishedWork.tag) {
case HostRoot:
recursivelyTraverseLayoutEffects(finishedRoot, finishedWork);
break;
case FunctionComponent: {
recursivelyTraverseLayoutEffects(finishedRoot, finishedWork);
if (flags & LayoutMask) {
// LayoutMask=Update=4
commitHookLayoutEffects(finishedWork, HookHasEffect | HookLayout);
}
break;
}
default:
break;
}
}
function commitHookLayoutEffects(finishedWork, hookFlags) {
commitHookEffectListMount(hookFlags, finishedWork);
}
function recursivelyTraverseLayoutEffects(root, parentFiber) {
if (parentFiber.subtreeFlags & LayoutMask) {
let child = parentFiber.child;
while (child !== null) {
const current = child.alternate;
commitLayoutEffectOnFiber(root, current, child);
child = child.sibling;
}
}
}
- ReactFiberHooks.js
const HooksDispatcherOnMount = {
useReducer: mountReducer,
useState: mountState,
useEffect: mountEffect,
useLayoutEffect: mountLayoutEffect,
};
const HooksDispatcherOnUpdate = {
useReducer: updateReducer,
useState: updateState,
useEffect: updateEffect,
useLayoutEffect: updateLayoutEffect,
};
function mountLayoutEffect(create, deps) {
return mountEffectImpl(UpdateEffect, HookLayout, create, deps);
}
function updateLayoutEffect(create, deps) {
return updateEffectImpl(UpdateEffect, HookLayout, create, deps);
}
fiber hooks