Skip to content

Commit 35c7b9e

Browse files
committed
Update on "[compiler] Recompute values every time"
Summary: This PR expands the analysis from the previous in the stack in order to also capture when a value can incorrectly change within a single render, rather than just changing between two renders. In the case where dependencies have changed and so a new value is being computed, we now compute the value twice and compare the results. This would, for example, catch when we call Math.random() in render. The generated code is a little convoluted, because we don't want to have to traverse the generated code and substitute variable names with new ones. Instead, we save the initial value to the cache as normal, then run the computation block again and compare the resulting values to the cached ones. Then, to make sure that the cached values are identical to the computed ones, we reassign the cached values into the output variables. [ghstack-poisoned]
2 parents e4d990b + 594801a commit 35c7b9e

File tree

2 files changed

+35
-6
lines changed

2 files changed

+35
-6
lines changed

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
blank_issues_enabled: false
12
contact_links:
23
- name: 📃 Documentation Issue
34
url: https://github.com/reactjs/react.dev/issues/new/choose

packages/react-client/src/ReactFlightClient.js

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ export type Response = {
254254
_rowLength: number, // remaining bytes in the row. 0 indicates that we're looking for a newline.
255255
_buffer: Array<Uint8Array>, // chunks received so far as part of this row
256256
_tempRefs: void | TemporaryReferenceSet, // the set temporary references can be resolved from
257+
_debugRootTask?: null | ConsoleTask, // DEV-only
257258
};
258259

259260
function readChunk<T>(chunk: SomeChunk<T>): T {
@@ -614,6 +615,7 @@ function getTaskName(type: mixed): string {
614615
}
615616

616617
function createElement(
618+
response: Response,
617619
type: mixed,
618620
key: mixed,
619621
props: mixed,
@@ -697,9 +699,15 @@ function createElement(
697699
const callStack = buildFakeCallStack(stack, createTaskFn);
698700
// This owner should ideally have already been initialized to avoid getting
699701
// user stack frames on the stack.
700-
const ownerTask = owner === null ? null : initializeFakeTask(owner);
702+
const ownerTask =
703+
owner === null ? null : initializeFakeTask(response, owner);
701704
if (ownerTask === null) {
702-
task = callStack();
705+
const rootTask = response._debugRootTask;
706+
if (rootTask != null) {
707+
task = rootTask.run(callStack);
708+
} else {
709+
task = callStack();
710+
}
703711
} else {
704712
task = ownerTask.run(callStack);
705713
}
@@ -1106,6 +1114,7 @@ function parseModelTuple(
11061114
// TODO: Consider having React just directly accept these arrays as elements.
11071115
// Or even change the ReactElement type to be an array.
11081116
return createElement(
1117+
response,
11091118
tuple[1],
11101119
tuple[2],
11111120
tuple[3],
@@ -1149,6 +1158,14 @@ export function createResponse(
11491158
_buffer: [],
11501159
_tempRefs: temporaryReferences,
11511160
};
1161+
if (supportsCreateTask) {
1162+
// Any stacks that appear on the server need to be rooted somehow on the client
1163+
// so we create a root Task for this response which will be the root owner for any
1164+
// elements created by the server. We use the "use server" string to indicate that
1165+
// this is where we enter the server from the client.
1166+
// TODO: Make this string configurable.
1167+
response._debugRootTask = (console: any).createTask('"use server"');
1168+
}
11521169
// Don't inline this call because it causes closure to outline the call above.
11531170
response._fromJSON = createFromJSONCallback(response);
11541171
return response;
@@ -1730,6 +1747,7 @@ function buildFakeCallStack<T>(stack: string, innerCall: () => T): () => T {
17301747
}
17311748

17321749
function initializeFakeTask(
1750+
response: Response,
17331751
debugInfo: ReactComponentInfo | ReactAsyncInfo,
17341752
): null | ConsoleTask {
17351753
if (taskCache === null || typeof debugInfo.stack !== 'string') {
@@ -1745,7 +1763,7 @@ function initializeFakeTask(
17451763
const ownerTask =
17461764
componentInfo.owner == null
17471765
? null
1748-
: initializeFakeTask(componentInfo.owner);
1766+
: initializeFakeTask(response, componentInfo.owner);
17491767

17501768
// eslint-disable-next-line react-internal/no-production-logging
17511769
const createTaskFn = (console: any).createTask.bind(
@@ -1755,7 +1773,12 @@ function initializeFakeTask(
17551773
const callStack = buildFakeCallStack(stack, createTaskFn);
17561774

17571775
if (ownerTask === null) {
1758-
return callStack();
1776+
const rootTask = response._debugRootTask;
1777+
if (rootTask != null) {
1778+
return rootTask.run(callStack);
1779+
} else {
1780+
return callStack();
1781+
}
17591782
} else {
17601783
return ownerTask.run(callStack);
17611784
}
@@ -1776,7 +1799,7 @@ function resolveDebugInfo(
17761799
// We eagerly initialize the fake task because this resolving happens outside any
17771800
// render phase so we're not inside a user space stack at this point. If we waited
17781801
// to initialize it when we need it, we might be inside user code.
1779-
initializeFakeTask(debugInfo);
1802+
initializeFakeTask(response, debugInfo);
17801803
const chunk = getChunk(response, id);
17811804
const chunkDebugInfo: ReactDebugInfo =
17821805
chunk._debugInfo || (chunk._debugInfo = []);
@@ -1813,12 +1836,17 @@ function resolveConsoleEntry(
18131836
printToConsole.bind(null, methodName, args, env),
18141837
);
18151838
if (owner != null) {
1816-
const task = initializeFakeTask(owner);
1839+
const task = initializeFakeTask(response, owner);
18171840
if (task !== null) {
18181841
task.run(callStack);
18191842
return;
18201843
}
18211844
}
1845+
const rootTask = response._debugRootTask;
1846+
if (rootTask != null) {
1847+
rootTask.run(callStack);
1848+
return;
1849+
}
18221850
callStack();
18231851
}
18241852

0 commit comments

Comments
 (0)