Introduction to the
- The react version v17.3
- Only functions, classes, native components.
SuspenseComponent
OffscreenComponent
. Such components are not written.
- Code simplification
- Keep only the core logic.
- **DIFF **
reconcileChildren
Do not speak. Know that new fiber will be generated.
The working process
In simple terms, it is depth first traversal (DFS) JSX tree, generating fiber tree. React converts a recursive process into a while loop.
Recurse to the while loop
WorkLoopSync, workLoopConcurrent
- The while loop
workInProgress
Perform performUnitOfWork- Each update
workInProgress
For the newfiber
- Each update
- performUnitOfWork
- beginWork
- completeUnitOfWork
- completeWork
// Synchronous mode
function workLoopSync() {
while(workInProgress ! = =null) { performUnitOfWork(workInProgress); }}// ConcurrentMode
function workLoopConcurrent() {
while(workInProgress ! = =null&&! shouldYield()) { performUnitOfWork(workInProgress); }}Copy the code
Recursive performUnitOfWork
- Start work => Create a work unit
fiber
。- Main Work:
childrenJSX
= >childrenFiber
。- Why is every job processing
children
?diff
The need for new and oldchildren
Compare them.- build
fiber
的sibling
return
And other information. dfs
Recursive”recursive“Go on. Each updateworkInProgress = childFber
。
- Why is every job processing
- Main Work:
- And then you end up with a tree
newFiberTree
。
// dfs
function performUnitOfWork(unitOfWork: Fiber) :void {
const current = unitOfWork.alternate;
/ / pass
let next = beginWork(current, unitOfWork, subtreeRenderLanes);
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
/ / return
completeUnitOfWork(unitOfWork);
} else{ workInProgress = next; }}Copy the code
Return completeUnitOfWork
- Finish the work =>
fiber
Tree buildinghost
Tree and render.- Main Work:
fiber
= >instance
. Creating host entities- How is “return” constructed
host
The tree?- Each time will be
childrenFiber
的instance
Added to theworkInProgress
的instance
In the.
- Each time will be
dfs
Recursive”Belong to the“Up, how?fiber
After completing the completeWork.- The new generation
workInProgress
- Move to the
sibling
return
- The new generation
- How is “return” constructed
- Main Work:
- And finally render
dom
树
function completeUnitOfWork(unitOfWork: Fiber) :void {
let completedWork = unitOfWork;
do {
const current = completedWork.alternate;
const returnFiber = completedWork.return;
let next = completeWork(current, completedWork, subtreeRenderLanes);
if(next ! = =null) {
workInProgress = next;
return;
}
const siblingFiber = completedWork.sibling;
if(siblingFiber ! = =null) {
// If there is more work to do in this returnFiber, do that next.
workInProgress = siblingFiber;
return;
}
// Otherwise, return to the parent
completedWork = returnFiber;
// Update the next thing we're working on in case something throws.
workInProgress = completedWork;
} while(completedWork ! = =null);
// We've reached the root.
if(workInProgressRootExitStatus === RootIncomplete) { workInProgressRootExitStatus = RootCompleted; }}Copy the code
Public variables
- didReceiveUpdate
- Function: False indicates that sub-fiber does not need update, true indicates that update is required.
- A function that modifies this value
- beginWork
- updateSimpleMemoComponent
- markWorkInProgressReceivedUpdate()
- Effect: didReceiveUpdate = true
- The person who calls this function
- renderWithHooks
- renderWithReducer
- updateReducer
- prepareToReadContext
- bailoutOnAlreadyFinishedWork
- workInProgress
- Fiber at work.
beginWork
Create childrenFiber with workinProgress.children (JSX) and return childFiber, the first child.
- Why is every job processing
children
?diff
The need for new and oldchildren
Compare them.- build
fiber
的sibling
return
And other information. dfs
Recursive”recursive“Go on. Each updateworkInProgress = childFber
。
- Logic:
- judge
workInProgress
If you needupdate
。- Determine whether there is
oldFiber
,- Being — judging old and new
props
Is it different,Fiber stack context
Whether to change- Props is different
- Need to update. didReceiveUpdate = false;
- Whether the same props
- If no current has interrupted updates.
- No updates needed. didReceiveUpdate = false;
- Return Clone Fiber (in other words, alternate, oldFiber)
- Determine if there is
forceUpdate
Forced to updateflags
- There are
- Need to update. didReceiveUpdate = false;
- There is no
- No updates needed. didReceiveUpdate = false;
- There are
- If no current has interrupted updates.
- Props is different
- Does not exist – means mount
- No updates needed. didReceiveUpdate = false;
- Being — judging old and new
- Determine whether there is
workInProgress
Task lane is reset to none- According to the
workInProgress
Type of worktag
Let’s go to the different work functions
- judge
function beginWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
) :Fiber | null {
if(current ! = =null) {
// update to check whether an update is required
const oldProps = current.memoizedProps;
const newProps = workInProgress.pendingProps;
if( oldProps ! == newProps ||// props is updated if different
// Force a re-render if the implementation changed due to hot reload:(__DEV__ ? workInProgress.type ! == current.type :false)
) {
didReceiveUpdate = true;
} else {
// Check whether the Lane context needs to be updated
const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(
current,
renderLanes,
);
if (
// No mandatory update! hasScheduledUpdateOrContext && (workInProgress.flags & DidCapture) === NoFlags ) { didReceiveUpdate =false;
// Clone the old fiber directly
return attemptEarlyBailoutIfNoScheduledUpdate(
current,
workInProgress,
renderLanes,
);
}
Suspense whether there are mandatory updates
if((current.flags & ForceUpdateForLegacySuspense) ! == NoFlags) { didReceiveUpdate =true;
} else {
didReceiveUpdate = false; }}}else {
// The mount phase is not updated
didReceiveUpdate = false;
}
// Start work, lane reset
workInProgress.lanes = NoLanes;
switch (workInProgress.tag) {
// The function component mounts with this tag. Modify the tag after the command is executed. For example, components that do not inherit from Component.
case IndeterminateComponent: {
return mountIndeterminateComponent(
current,
workInProgress,
workInProgress.type,
renderLanes,
);
}
// Function components
case FunctionComponent: {
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps =
workInProgress.elementType === Component
? unresolvedProps
: resolveDefaultProps(Component, unresolvedProps);
return updateFunctionComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes,
);
}
/ / class components
case ClassComponent: {
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps =
workInProgress.elementType === Component
? unresolvedProps
: resolveDefaultProps(Component, unresolvedProps);
return updateClassComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes,
);
}
// Native component div, etc
case HostComponent:
return updateHostComponent(current, workInProgress, renderLanes);
case HostText:
return updateHostText(current, workInProgress);
}
Copy the code
Different worker functions tag -> worker functions
The Reconcile Child is a Diff.
HostComponent -> updateHostComponent
Introduction to the
- Handles native components, as in the browser
DOM
。
function
- generate
childrenFiber
- Performance optimization: If the child is a single text node, then the child does not generate fiber.
logic
- Whether children are single-text nodes
- A single text
- Offspring are not generated
fiber
. nextChildren = null
- Offspring are not generated
- Not single text
- if
oldFiber
A single text- Mark content clearing
ContentReset
- Mark content clearing
- if
- A single text
markRef
Whether the tag is requiredref
reconcileChildren
diff- return
workInProgress.child
function updateHostComponent(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
) {
const type = workInProgress.type;
const nextProps = workInProgress.pendingProps;
constprevProps = current ! = =null ? current.memoizedProps : null;
let nextChildren = nextProps.children;
Eg
children has only one text node
const isDirectTextChild = shouldSetTextContent(type, nextProps);
if (isDirectTextChild) {
// The text node does not generate fiber, and the text is rendered directly in commit
nextChildren = null;
} else if(prevProps ! = =null && shouldSetTextContent(type, prevProps)) {
workInProgress.flags |= ContentReset;
}
markRef(current, workInProgress);
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
Copy the code
HostText -> updateHostText
Return NULL without doing anything.
IndeterminateComponent -> mountIndeterminateComponent
Introduction to the
function
componentmount
, take this function. Products left over from history.
function
- generate
childrenFiber
- Compatibility: Dealing with old React support factories (
factory
) function that isFunction
Return to haveclass
Object of a component method.
logic
- Obtained when the function component executes renderWithHooks
value
- judge
value
Whether it is an object that emulates factory Class.- is
factory class
tag
Revised toClassComponent
- create
The class components
- return finishClassComponent
- Whether is
Function component
tag
Revised toFunctionComponent
- reconcileChildren
- return
workInProgress.child
- is
function mountIndeterminateComponent(_current, workInProgress, Component, renderLanes,) {
const props = workInProgress.pendingProps;
let context;
// Clear the previous context
prepareToReadContext(workInProgress, renderLanes);
// Run the component function
value = renderWithHooks(
null,
workInProgress,
Component,
props,
context,
renderLanes,
);
// Determine whether the function returns a clAS-like object with the render method
if (
!disableModulePatternComponents &&
typeof value === 'object'&& value ! = =null &&
typeof value.render === 'function' &&
value.$$typeof === undefined
) {
// Treat this fiber as ClassComponent
workInProgress.tag = ClassComponent;
workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
let hasContext = false;
if (isLegacyContextProvider(Component)) {
hasContext = true;
pushLegacyContextProvider(workInProgress);
} else {
hasContext = false; } workInProgress.memoizedState = value.state ! = =null&& value.state ! = =undefined ? value.state : null;
initializeUpdateQueue(workInProgress);
adoptClassInstance(workInProgress, value);
mountClassInstance(workInProgress, Component, props, renderLanes);
return finishClassComponent(
null,
workInProgress,
Component,
true,
hasContext,
renderLanes,
);
} else {
// Handle as FunctionComponent
workInProgress.tag = FunctionComponent;
// diff
reconcileChildren(null, workInProgress, value, renderLanes);
returnworkInProgress.child; }}Copy the code
FunctionComponent -> updateFunctionComponent
Introduction to the
function
componentupdate
, take this function.- Build the hooks
function
- generate
childrenFiber
logic
- prepareToReadContext
- RenderWithHooks get
nextChildren
- if
current
There is,didReceiveUpdate
为flase
No update is required.- bailoutHooks
- return bailoutOnAlreadyFinishedWork
- You need to update
- reconcileChildren
- return
workInProgress.child
function updateFunctionComponent(
current,
workInProgress,
Component,
nextProps: any,
renderLanes,
) {
let context;
if(! disableLegacyContext) {const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
context = getMaskedContext(workInProgress, unmaskedContext);
}
let nextChildren;
// Clear the previous context
prepareToReadContext(workInProgress, renderLanes);
// Run the component function
nextChildren = renderWithHooks(
current,
workInProgress,
Component,
nextProps,
context,
renderLanes,
);
// Whether an update is required
if(current ! = =null && !didReceiveUpdate) {
bailoutHooks(current, workInProgress, renderLanes);
// Clone the old fiber
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
// diff
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
Copy the code
ClassComponent -> updateClassComponent
Introduction to the
class
The component uses this function.
function
- Process the life cycle.
- generate
childrenFiber
logic
- PrepareToReadContext – clear context
- if
mount
. fiber.stateNode === null; The stateNode value of the class component is the class instance.- constructClassInstance
- read
context
. readContext - Execute constructor
constructor
。 - The assignment
state
. fiber.memoizedState = instance.state
- read
- mountClassInstance
fiber
Initialize theupdateQueue
. initializeUpdateQueuecontext
Assign values to theinstance.context
- ** Life cycle **
- applyDerivedStateFromProps(
getDerivedStateFromProps
)- update
instance.state
、Fiber. MemoizedState and ` ` updateQueue baseState
- update
- If only
componentWillMount
And no newLifecycles
,getDerivedStateFromProps
或getSnapshotBeforeUpdate
- Perform callComponentWillMount
componentWillMount
- classComponentUpdater.enqueueReplaceState
- processUpdateQueue
- update
instance.state
- Perform callComponentWillMount
- applyDerivedStateFromProps(
- shouldUpdate = true;
- constructClassInstance
- if
update
- shouldUpdate = updateClassInstance
- If it had no new
Lifecycles
executecomponentWillReceiveProps
— callComponentWillReceiveProps- After execution, if
newState ! == oldState
- classComponentUpdater.enqueueReplaceState
- enqueueUpdate
- classComponentUpdater.enqueueReplaceState
- After execution, if
- Batch update, calculation
newState
. —processUpdateQueue()
- The assignment
fiber.memoizedState
- Ability to handle priorities
- The assignment
- ** Life cycle **
getDerivedStateFromProps()
- If you need to update
- ** Life cycle **
componentWillUpdate()
- ** Life cycle **
- If it needs to be updated and exists
componentDidUpdate()
getSnapshotBeforeUpdate()
- the
fibet.flags
writeUpdate
/Snapshot
- the
- update
fibet.memoizedProps
fiber.memoizedState
- Class instance update,
- update
instace
的props
state
context
- update
- return shouldUpdate;
- If it had no new
- shouldUpdate = updateClassInstance
- finishClassComponent
- No need to update
- bailoutOnAlreadyFinishedWork
- You need to update
- reconcileChildren
- No need to update
- return
workInProgress.child
function updateClassComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any,
nextProps: any,
renderLanes: Lanes,
) {
/ / to empty the context
prepareToReadContext(workInProgress, renderLanes);
const instance = workInProgress.stateNode;
let shouldUpdate;
if (instance === null) {
if(current ! = =null) {
current.alternate = null;
workInProgress.alternate = null;
workInProgress.flags |= Placement;
}
// Read the context, execute the constructor, and assign state
constructClassInstance(workInProgress, Component, nextProps);
// fiber initializes the updateQueue and assigns the context to the instance
mountClassInstance(workInProgress, Component, nextProps, renderLanes);
shouldUpdate = true;
} else if (current === null) {
// Reuse the instance
shouldUpdate = resumeMountClassInstance(
workInProgress,
Component,
nextProps,
renderLanes,
);
} else {
// Calculate state, execute and update the associated lifecycle
shouldUpdate = updateClassInstance(
current,
workInProgress,
Component,
nextProps,
renderLanes,
);
}
// diff does not need to update, clone
const nextUnitOfWork = finishClassComponent(
current,
workInProgress,
Component,
shouldUpdate,
hasContext,
renderLanes,
);
return nextUnitOfWork;
}
Copy the code
Fragment -> updateFragment
Introduction to the
- Working with Fragment components
- PendingProps is childrenJSX
function
- generate
childrenFiber
logic
- reconcileChildren
- return
workInProgress.child
function updateFragment(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
) {
const nextChildren = workInProgress.pendingProps;
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
Copy the code
updateHostRoot
Create the react component root.
- The Reconciler coordination
rootFiber
Through thereconcileChildren
和jsx
To buildchildren fiber
returnchild fiber
。
Logic:
fiberRoot
的state.element
A value ofjsx
, i.e.,ReactDOM.render
The first value in.- through
state.element
来reconcileChildren
CompleteWork
Create/update stateNode for workInProgress. Add all the Statenodes for childrenFiber to workinProgress.statenode. SubtreeFlags, childLanes bubbles up. When mount: create DOM, set property update: diff props, create updateQueue Commit.
- Why all
child
thestateNode
Added to theworkInProgress.stateNode
In the?- Root will eventually form a DOM tree, which can be inserted directly into the DOM tree.
- Logic:
- According to the
workInProgress
Type of worktag
Enter different switch blocks- The main job is processing
HostComponent
. - Class Function components bubble up only
flags
.lane
.bubbleProperties
.
- The main job is processing
- According to the
Different work functions tag -> switch block
HostComponent
function
- Create/update the DOM
logic
- If update.
current ! == null && workInProgress.stateNode ! = null
updateHostComponent
- New and old props will be updated if they differ.
workInProgress.updateQueue = prepareUpdate
- for
dom
Properties of thediff
updatePayload
([key,value] array, I for modified attribute, I +1 for modified value)/null
- for
- The old ref is different from the old ref,
markRef
- If for creating
createInstance
- Create dom
appendAllChildren
- will
childrenFiber
的stateNode
Add all toworkInProgress.stateNode
中
- will
finalizeInitialChildren
- Set properties.
- Handles the case where the child node is a single text node. setTextContent(domElement, nextProp)
- Set properties.
markRef
bubbleProperties
- return null
const rootContainerInstance = getRootHostContainer();
const type = workInProgress.type;
if(current ! = =null&& workInProgress.stateNode ! =null) {
updateHostComponent(
current,
workInProgress,
type,
newProps,
rootContainerInstance,
);
if (current.ref !== workInProgress.ref) {
markRef(workInProgress);
}
} else {
// mount dom inserts
const currentHostContext = getHostContext();
const instance = createInstance(
type,
newProps,
rootContainerInstance,
currentHostContext,
workInProgress,
);
appendAllChildren(instance, workInProgress, false.false);
workInProgress.stateNode = instance;
if (
finalizeInitialChildren(instance,type,newProps,rootContainerInstance,currentHostContext,)
) {
markUpdate(workInProgress);
}
if(workInProgress.ref ! = =null) {
markRef(workInProgress);
}
}
bubbleProperties(workInProgress);
return null;
Copy the code
HostText -> updateHostText
function
- Create/update the text node
logic
- If update.
current ! == null && workInProgress.stateNode ! = null
updateHostText
- Mark the Update.
- If for creating
createTextInstance
- Create a Text node
bubbleProperties
- return null
const newText = newProps;
if(current && workInProgress.stateNode ! =null) {
const oldText = current.memoizedProps;
// flags writes update
updateHostText(current, workInProgress, oldText, newText);
} else {
const rootContainerInstance = getRootHostContainer();
const currentHostContext = getHostContext();
// Create a text node
workInProgress.stateNode = createTextInstance(
newText,
rootContainerInstance,
currentHostContext,
workInProgress,
);
}
Copy the code
bubbleProperties
Fiber attribute subtreeFlags childLanes bubble
subtreeFlags
mergechildren
theflags
和subtreeFlags
childLanes
mergechildren
的lane
和childLane
Each fiber has subtreeFlags and childLanes for its subtrees
CommitRoot
Render the Fiber tree and perform the phases.
- To deal with
useEffect
.uesLayoutEffect
- To deal with
class
中getSnapshotBeforeUpdate
.componentDidMount
.componentDidUpdate
.componentWillUnmount
- The assignment
ref
- Execute sequentially (
this.setState
.ReactDOM.render
The callback - Modify the view DOM.
Placement
.Update
.Deletion
.
Logic:
- Ideas:
- Each phase is iterated
root.finishedWork
- is
render
Phase completes the construction of the new Fibet tree. - Value is
root.current.alternate
- is
- Each DFS fiber tree, perform the related phase of work
- Performance optimization:
subtreeFlags
与At this stageThe relevantFlags
Compared toNoFlags
This subtree is skipped
- Each phase is iterated
To deal withuseEffect
— Attention!! Scheduling, next macro task execution
scheduleCallback
(flushPassiveEffects
)- scheduler
useEffect
Destroy and create - To destroy –
commitPassiveUnmountEffects
- In the create –
commitPassiveMountEffects
- scheduler
scheduleCallback(NormalSchedulerPriority, () = > {
UseEffect destory is executed in create
flushPassiveEffects();
return null;
});
Copy the code
BeforMutation
Stage – before the page changes –commitBeforeMutationEffects
- Function:
- DFS Fiber tree, run
getSnapshotBeforeUpdate
- DFS Fiber tree, run
- Logic:
commitBeforeMutationEffects_begin
commitBeforeMutationEffects_complete
commitBeforeMutationEffectsOnFiber
- perform
commitBeforeMutationEffects
- To deal with
Snapshot
, i.e.,getSnapshotBeforeUpdate
. No other operation is performed temporarily
- perform
**Mutation**
** stage ** — the page is changing —commitMutationEffects
- Function:
- DFS Fiber tree, processing
Delete
Plcament
Update
- DFS Fiber tree, processing
- Logic:
commitMutationEffects_begin
- First deal with the deleted fiber
- if
fiber.deletions
Exists, then loopDelete
Each fiber- Note: Removed fiber is not present
finishedFiberTree
Only inreturnFiber.deletions
中 commitDeletion
commitNestedUnmounts
- FunctionComponent :
layoutEffect destroy
- ClassComponent:
componentWillUnmount
- HostConpmentEmpty:
ref
- FunctionComponent :
detachFiberMutation
- Fiber, alternate return empty
- Note: Removed fiber is not present
- if
commitMutationEffects_complete
commitMutationEffectsOnFiber
- judge
flags
To perform the work-
ContentReset
- Clear text
-
Ref
- Clearing ref.layout reassigns
-
Visibility
-
Plcament
commitPlacement
stateNode
inserthost
-
Update
commitWork
- FunctionComponent:
layoutEffect destroy
- HostComponent: Update attributes
- commitUpdate updateQueue
- Handling Children is an optimization of a single text node
- HostText: update text
- FunctionComponent:
-
- judge
- First deal with the deleted fiber
- Function:
function commitMutationEffects_begin(root: FiberRoot) {
while(nextEffect ! = =null) {
const fiber = nextEffect;
const deletions = fiber.deletions;
// Deletions does not exist in the finishedWork fiber tree.
// Because it will not be reused during diff
if(deletions ! = =null) {
for (let i = 0; i < deletions.length; i++) {
const childToDelete = deletions[i];
// DFS immediately delete fiber
// function : effect destroy
// class: componentWillUnmount
// host: clear ref
// Then uninstall stateNodecommitDeletion(root, childToDelete, fiber); }}const child = fiber.child;
// Performance optimization: If there is no task in subtreeFlags, go straight to Fiber, skip subtree, go up "back ",
if((fiber.subtreeFlags & MutationMask) ! == NoFlags && child ! = =null) {
nextEffect = child;
} else {
// Skip the no task subtree
// No task subtree or leaf nodecommitMutationEffects_complete(root); }}}function commitMutationEffects_complete(root: FiberRoot) {
while(nextEffect ! = =null) {
const fiber = nextEffect;
commitMutationEffectsOnFiber(fiber, root);
/ / (switch
const sibling = fiber.sibling;
if(sibling ! = =null) {
nextEffect = sibling;
return;
}
Switch / / returnnextEffect = fiber.return; }}function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) {
const flags = finishedWork.flags;
if (flags & ContentReset) {
// Empty the text
commitResetTextContent(finishedWork);
}
if (flags & Ref) {
const current = finishedWork.alternate;
/ / clear the ref
if(current ! = =null) { commitDetachRef(current); }}// New features are skipped first
if (flags & Visibility) {}
const primaryFlags = flags & (Placement | Update | Hydrating);
outer: switch (primaryFlags) {
case Placement: {
// DOM insert resets the text if there is a Flags ContentReset
commitPlacement(finishedWork);
finishedWork.flags &= ~Placement;
break;
}
case PlacementAndUpdate: {
commitPlacement(finishedWork);
finishedWork.flags &= ~Placement;
const current = finishedWork.alternate;
/ / update
// layoutEffect destroy
// hostComponent updates properties
// hostText Updates text
commitWork(current, finishedWork);
break;
}
case Update: {
const current = finishedWork.alternate;
commitWork(current, finishedWork);
break; }}}Copy the code
- root.current = finishedWork;
- When you’re done, switch the tree
- Why switch here?
- Before that, the old
fiber
Tree work depends on- Eg:
mutation
In the stage ofcomponentWillUnmount
It relies on the old Fiber tree, so it doesn’t switch
- Eg:
- after
layout
Phase, eg:componentDidMount
andcomponentDidUpdate
It depends on the new Fiber tree, so switch the Fiber tree
- Before that, the old
Layout stage — after the page changescommitLayoutEffects
- Function:
- DFS Fiber tree, processing
componentDidMount
、componentDidUpdate
、layoutEffect create
、ref
- Callback to perform the setState of class
- DFS Fiber tree, processing
- Logic:
commitLayoutEffects_begin
- To deal with
OffscreenComponent
- To deal with
commitLayoutMountEffects_complete
commitLayoutEffectOnFiber
commitHookEffectListMount
- Function:
layoutEffect create
- Class:
componentDidUpdate
/componentDidMount
- Judge curren from mount/update
- perform
this.setState
Callback – commitUpdateQueue
- HostComponent: the Renderer —
commitMount
- The Renderer may need to perform tasks
- Function:
- commitAttachRef
- Update the ref
// DFS with similar Mutation
function commitLayoutEffectOnFiber(
finishedRoot: FiberRoot,
current: Fiber | null,
finishedWork: Fiber,
committedLanes: Lanes,
) :void {
if((finishedWork.flags & LayoutMask) ! == NoFlags) {switch (finishedWork.tag) {
case FunctionComponent: {
// layoutEffect create
commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
break;
}
case ClassComponent: {
const instance = finishedWork.stateNode;
if (finishedWork.flags & Update) {
if (current === null) {
// Life Cycle componentDidMount
instance.componentDidMount();
} else {
const prevProps =
finishedWork.elementType === finishedWork.type
? current.memoizedProps
: resolveDefaultProps(
finishedWork.type,
current.memoizedProps,
);
const prevState = current.memoizedState;
// Life Cycle componentDidUpdateinstance.componentDidUpdate( prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate, ); }}const updateQueue = (finishedWork.updateQueue: any);
if(updateQueue ! = =null) {
// This. SetState callback queue
commitUpdateQueue(finishedWork, updateQueue, instance);
}
break;
}
case HostRoot: {
const updateQueue: UpdateQueue<*,
> | null = (finishedWork.updateQueue: any);
if(updateQueue ! = =null) {
let instance = null;
if(finishedWork.child ! = =null) {
switch (finishedWork.child.tag) {
case HostComponent:
instance = getPublicInstance(finishedWork.child.stateNode);
break;
case ClassComponent:
instance = finishedWork.child.stateNode;
break;
}
}
commitUpdateQueue(finishedWork, updateQueue, instance);
}
break;
}
case HostComponent: {
const instance: Instance = finishedWork.stateNode;
if (current === null && finishedWork.flags & Update) {
const type = finishedWork.type;
const props = finishedWork.memoizedProps;
// React-dom executes focus after mount
commitMount(instance, type, props, finishedWork);
}
break; }}if (finishedWork.flags & Ref) {
/ / refcommitAttachRef(finishedWork); }}Copy the code
commit
Phases may generate new tasks for processing.ensureRootIsScheduled
flushSyncCallbacks
UseEffect and useLayoutEffect
phase | useEffect | useLayoutEffect |
---|---|---|
beforeMutation | There is no | There is no |
mutation | There is no | Execute deStory (destroy function) |
layout | There is no | Execute create (useLayoutEffect) |
Next macro task | Run flushPassiveEffects, that is, destory, create | There is no |
UseLayoutEffect is executed synchronously. UseEffect is executed asynchronously after a commit