Skip to content

Commit ccb260e

Browse files
committed
Use forked implementation of performWork
1 parent 1dd02bd commit ccb260e

File tree

2 files changed

+60
-13
lines changed

2 files changed

+60
-13
lines changed

packages/react-server/src/ReactFizzServer.js

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,25 +1029,66 @@ function pushHaltedAwaitOnComponentStack(
10291029
}
10301030
}
10311031

1032+
// performWork + retryTask without mutation
1033+
function rerenderHaltedTask(request: Request, task: Task): void {
1034+
const prevContext = getActiveContext();
1035+
const prevDispatcher = ReactSharedInternals.H;
1036+
ReactSharedInternals.H = HooksDispatcher;
1037+
const prevAsyncDispatcher = ReactSharedInternals.A;
1038+
ReactSharedInternals.A = DefaultAsyncDispatcher;
1039+
1040+
const prevRequest = currentRequest;
1041+
currentRequest = request;
1042+
1043+
const prevGetCurrentStackImpl = ReactSharedInternals.getCurrentStack;
1044+
ReactSharedInternals.getCurrentStack = getCurrentStackInDEV;
1045+
1046+
const prevResumableState = currentResumableState;
1047+
setCurrentResumableState(request.resumableState);
1048+
switchContext(task.context);
1049+
const prevTaskInDEV = currentTaskInDEV;
1050+
setCurrentTaskInDEV(task);
1051+
try {
1052+
retryNode(request, task);
1053+
} catch (x) {
1054+
// Suspended again.
1055+
resetHooksState();
1056+
} finally {
1057+
setCurrentTaskInDEV(prevTaskInDEV);
1058+
setCurrentResumableState(prevResumableState);
1059+
1060+
ReactSharedInternals.H = prevDispatcher;
1061+
ReactSharedInternals.A = prevAsyncDispatcher;
1062+
1063+
ReactSharedInternals.getCurrentStack = prevGetCurrentStackImpl;
1064+
if (prevDispatcher === HooksDispatcher) {
1065+
// This means that we were in a reentrant work loop. This could happen
1066+
// in a renderer that supports synchronous work like renderToString,
1067+
// when it's called from within another renderer.
1068+
// Normally we don't bother switching the contexts to their root/default
1069+
// values when leaving because we'll likely need the same or similar
1070+
// context again. However, when we're inside a synchronous loop like this
1071+
// we'll to restore the context to what it was before returning.
1072+
switchContext(prevContext);
1073+
}
1074+
currentRequest = prevRequest;
1075+
}
1076+
}
1077+
10321078
function pushSuspendedCallSiteOnComponentStack(
10331079
request: Request,
10341080
task: Task,
10351081
): void {
10361082
setCaptureSuspendedCallSiteDEV(true);
1037-
let suspendCallSiteStack: ComponentStackNode | null = null;
1038-
let suspendCallSiteDebugTask: ConsoleTask | null = null;
1039-
const previousPingedTasks = request.pingedTasks;
10401083
try {
1041-
// TODO: Use a dedicated method to re-render instead of abusing ping.
1042-
request.pingedTasks = [task];
1043-
performWork(request);
1044-
suspendCallSiteStack = getSuspendedCallSiteStackDEV();
1045-
suspendCallSiteDebugTask = getSuspendedCallSiteDebugTaskDEV();
1084+
rerenderHaltedTask(request, task);
10461085
} finally {
1047-
request.pingedTasks = previousPingedTasks;
10481086
setCaptureSuspendedCallSiteDEV(false);
10491087
}
10501088

1089+
const suspendCallSiteStack = getSuspendedCallSiteStackDEV();
1090+
const suspendCallSiteDebugTask = getSuspendedCallSiteDebugTaskDEV();
1091+
10511092
if (suspendCallSiteStack !== null) {
10521093
const ownerStack = task.componentStack;
10531094
task.componentStack = {
@@ -4996,9 +5037,7 @@ function retryRenderTask(
49965037
task: RenderTask,
49975038
segment: Segment,
49985039
): void {
4999-
// TODO: We only retry when aborted to get the suspended callsite.
5000-
// Use a dedicated mechanism to re-render.
5001-
if (segment.status !== PENDING && segment.status !== ABORTED) {
5040+
if (segment.status !== PENDING) {
50025041
// We completed this by other means before we had a chance to retry it.
50035042
return;
50045043
}

packages/react-server/src/__tests__/ReactServer-test.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,13 @@ describe('ReactServer', () => {
4949
});
5050

5151
it('has Owner Stacks in DEV when aborted', async () => {
52+
const Context = React.createContext(null);
53+
5254
function Component({promise}) {
55+
const context = React.use(Context);
56+
if (context === null) {
57+
throw new Error('Missing context');
58+
}
5359
React.use(promise);
5460
return <div>Hello, Dave!</div>;
5561
}
@@ -61,7 +67,9 @@ describe('ReactServer', () => {
6167
let componentStack;
6268
let ownerStack;
6369
const result = ReactNoopServer.render(
64-
<App promise={new Promise(() => {})} />,
70+
<Context value="provided">
71+
<App promise={new Promise(() => {})} />
72+
</Context>,
6573
{
6674
onError: (error, errorInfo) => {
6775
caughtError = error;

0 commit comments

Comments
 (0)