useEffect更新
packages/react-reconciler/src/ReactFiberHooks.js
js
function updateEffect(create, deps) {
return updateEffectImpl(PassiveEffect, HookPassive, create, deps);
}
function updateEffectImpl(fiberFlags, hookFlags, create, deps) {
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
let destroy;
if (currentHook !== null) {
const prevEffect = currentHook.memoizedState;
destroy = prevEffect.destroy;
if (nextDeps !== null) {
const prevDeps = prevEffect.deps;
if (areHookInputsEqual(nextDeps, prevDeps)) {
hook.memoizedState = pushEffect(hookFlags, create, destroy, nextDeps);
return;
}
}
}
currentlyRenderingFiber.flags |= fiberFlags;
hook.memoizedState = pushEffect(HookHasEffect | hookFlags, create, destroy, nextDeps);
}
function areHookInputsEqual(nextDeps, prevDeps) {
if (prevDeps === null)
return null;
for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
if (Object.is(nextDeps[i], prevDeps[i])) {
continue;
}
return false;
}
return true;
}diff
export function renderWithHooks(current, workInProgress, Component, props) {
currentlyRenderingFiber = workInProgress; // 设置当前正在渲染的fiber节点
+ workInProgress.updateQueue = null;
if (current !== null && current.memoizedState !== null) {
ReactCurrentDispatcher.current = HooksDispatcherOnUpdate;
} else {
ReactCurrentDispatcher.current = HooksDispatcherOnMount;
}
const children = Component(props); // 通过组件和props渲染子节点
currentlyRenderingFiber = null;
workInProgressHook = null;
currentHook = null;
return children; // 返回子节点
}packages/react-reconciler/src/ReactFiberWorkLoop.js
js
import {
commitMutationEffectsOnFiber,
commitPassiveUnmountEffects,
commitPassiveMountEffects
} from './ReactFiberCommitWork';
let rootDoesHavePassiveEffect = false;
let rootWithPendingPassiveEffects = null;
function flushPassiveEffect() {
if (rootWithPendingPassiveEffects !== null) {
const root = rootWithPendingPassiveEffects;
commitPassiveUnmountEffects(root.current);
commitPassiveMountEffects(root, root.current);
}
}diff
function commitRoot(root) {
const { finishedWork } = root;
+ if ((finishedWork.subtreeFlags & Passive) !== NoFlags || (finishedWork.flags & Passive) !== NoFlags) {
+ if (!rootDoesHavePassiveEffect) {
+ rootDoesHavePassiveEffect = true;
+ scheduleCallback(flushPassiveEffect);
+ }
+ }
const subtreeHasEffects = (finishedWork.subtreeFlags & MutationMask) !== NoFlags;
const rootHasEffect = (finishedWork.flags & MutationMask) !== NoFlags;
if (subtreeHasEffects || rootHasEffect) {
commitMutationEffectsOnFiber(finishedWork, root);
+ if (rootDoesHavePassiveEffect) {
+ rootDoesHavePassiveEffect = false;
+ rootWithPendingPassiveEffects = root;
+ }
}
root.current = finishedWork;
}packages/react-reconciler/src/ReactFiberCommitWork.js
js
import { Placement, MutationMask, Update, Passive } from "./ReactFiberFlags";
import { HasEffect as HookHasEffect, Passive as HookPassive } from './ReactHookEffectTags';
export function commitPassiveUnmountEffects(finishedWork) {
commitPassiveUnmountOnFiber(finishedWork);
}
function commitPassiveUnmountOnFiber(finishedWork) {
const flags = finishedWork.flags;
switch (finishedWork.tag) {
case HostRoot: {
recursivelyTraversePassiveUnmountEffects(finishedWork);
break;
}
case FunctionComponent: {
recursivelyTraversePassiveUnmountEffects(finishedWork);
if (flags & Passive) {
commitHookPassiveUnmountEffects(finishedWork, HookHasEffect | HookPassive);
}
break;
}
}
}
function recursivelyTraversePassiveUnmountEffects(parentFiber) {
if (parentFiber.subtreeFlags & Passive) {
let child = parentFiber.child;
while (child !== null) {
commitPassiveUnmountOnFiber(child);
child = child.sibling;
}
}
}
function commitHookPassiveUnmountEffects(finishedWork, hookFlags) {
commitHookEffectListUnmount(hookFlags, finishedWork);
}
function commitHookEffectListUnmount(flags, finishedWork) {
const updateQueue = finishedWork.updateQueue;
const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
const firstEffect = lastEffect.next;
let effect = firstEffect;
do {
if ((effect.tag & flags) === flags) {
const destroy = effect.destroy;
if (destroy !== undefined) {
destroy();
}
}
effect = effect.next;
} while (effect !== firstEffect)
}
}
export function commitPassiveMountEffects(root, finishedWork) {
commitPassiveMountOnFiber(root, finishedWork);
}
function commitPassiveMountOnFiber(finishedRoot, finishedWork) {
const flags = finishedWork.flags;
switch (finishedWork.tag) {
case HostRoot: {
recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork);
break;
}
case FunctionComponent: {
recursivelyTraversePassiveMountEffects(finishedRoot, finishedWork);
if (flags & Passive) {
commitHookPassiveMountEffects(finishedWork, HookHasEffect | HookPassive);
}
break;
}
}
}
function recursivelyTraversePassiveMountEffects(root, parentFiber) {
if (parentFiber.subtreeFlags & Passive) {
let child = parentFiber.child;
while (child !== null) {
commitPassiveMountOnFiber(root, child);
child = child.sibling;
}
}
}
function commitHookPassiveMountEffects(finishedWork, hookFlags) {
commitHookEffectListMount(hookFlags, finishedWork);
}
function commitHookEffectListMount(flags, finishedWork) {
const updateQueue = finishedWork.updateQueue;
const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
const firstEffect = lastEffect.next;
let effect = firstEffect;
do {
if ((effect.tag & flags) === flags) {
const create = effect.create;
effect.destroy = create();
}
effect = effect.next;
} while (effect !== firstEffect)
}
}