Skip to content

Commit

Permalink
Add replayForwardRef
Browse files Browse the repository at this point in the history
  • Loading branch information
hansottowirtz committed Apr 2, 2023
1 parent 353e360 commit 56b9a11
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 13 deletions.
54 changes: 50 additions & 4 deletions packages/react-reconciler/src/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,52 @@ function updateForwardRef(
return workInProgress.child;
}

export function replayForwardRef(
current: Fiber | null,
workInProgress: Fiber,
nextProps: any,
Component: any,
renderLanes: Lanes,
): Fiber | null {
const secondArg = workInProgress.ref;

// This function is used to replay a component that previously suspended,
// after its data resolves. It's a simplified version of
// updateFunctionComponent that reuses the hooks from the previous attempt.

prepareToReadContext(workInProgress, renderLanes);
if (enableSchedulingProfiler) {
markComponentRenderStarted(workInProgress);
}
const nextChildren = replaySuspendedComponentWithHooks(
current,
workInProgress,
Component,
nextProps,
secondArg,
);

// the rest is a fork of updateFunctionComponent
const hasId = checkDidRenderIdHook();
if (enableSchedulingProfiler) {
markComponentRenderStopped();
}

if (current !== null && !didReceiveUpdate) {
bailoutHooks(current, workInProgress, renderLanes);
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}

if (getIsHydrating() && hasId) {
pushMaterializedTreeId(workInProgress);
}

// React DevTools reads this flag.
workInProgress.flags |= PerformedWork;
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}

function updateMemoComponent(
current: Fiber | null,
workInProgress: Fiber,
Expand Down Expand Up @@ -1169,15 +1215,15 @@ export function replayFunctionComponent(
nextProps: any,
Component: any,
renderLanes: Lanes,
secondArg: any,
): Fiber | null {
// This function is used to replay a component that previously suspended,
// after its data resolves. It's a simplified version of
// updateFunctionComponent that reuses the hooks from the previous attempt.

if (!disableLegacyContext && secondArg === undefined) {
let context: any;
if (!disableLegacyContext) {
const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
secondArg = getMaskedContext(workInProgress, unmaskedContext);
context = getMaskedContext(workInProgress, unmaskedContext);
}

prepareToReadContext(workInProgress, renderLanes);
Expand All @@ -1189,7 +1235,7 @@ export function replayFunctionComponent(
workInProgress,
Component,
nextProps,
secondArg,
context,
);
const hasId = checkDidRenderIdHook();
if (enableSchedulingProfiler) {
Expand Down
32 changes: 23 additions & 9 deletions packages/react-reconciler/src/ReactFiberWorkLoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ import {
SelectiveHydrationException,
beginWork as originalBeginWork,
replayFunctionComponent,
replayForwardRef,
} from './ReactFiberBeginWork';
import {completeWork} from './ReactFiberCompleteWork';
import {unwindWork, unwindInterruptedWork} from './ReactFiberUnwindWork';
Expand Down Expand Up @@ -2380,18 +2381,12 @@ function replaySuspendedUnitOfWork(unitOfWork: Fiber): void {
// Fallthrough to the next branch.
}
// eslint-disable-next-line no-fallthrough
case FunctionComponent:
case ForwardRef: {
case FunctionComponent: {
// Resolve `defaultProps`. This logic is copied from `beginWork`.
// TODO: Consider moving this switch statement into that module. Also,
// could maybe use this as an opportunity to say `use` doesn't work with
// `defaultProps` :)
const Component =
unitOfWork.tag === FunctionComponent
? unitOfWork.type
: unitOfWork.type.render;
const secondArg =
unitOfWork.tag === FunctionComponent ? undefined : unitOfWork.ref;
const Component = unitOfWork.type;
const unresolvedProps = unitOfWork.pendingProps;
const resolvedProps =
unitOfWork.elementType === Component
Expand All @@ -2403,7 +2398,26 @@ function replaySuspendedUnitOfWork(unitOfWork: Fiber): void {
resolvedProps,
Component,
workInProgressRootRenderLanes,
secondArg,
);
break;
}
case ForwardRef: {
// Resolve `defaultProps`. This logic is copied from `beginWork`.
// TODO: Consider moving this switch statement into that module. Also,
// could maybe use this as an opportunity to say `use` doesn't work with
// `defaultProps` :)
const Component = unitOfWork.type.render;
const unresolvedProps = unitOfWork.pendingProps;
const resolvedProps =
unitOfWork.elementType === Component
? unresolvedProps
: resolveDefaultProps(Component, unresolvedProps);
next = replayForwardRef(
current,
unitOfWork,
resolvedProps,
Component,
workInProgressRootRenderLanes,
);
break;
}
Expand Down

0 comments on commit 56b9a11

Please sign in to comment.