Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] main from facebook:main #47

Merged
merged 4 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/react-dom-bindings/src/client/validateDOMNesting.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,8 @@ function isTagValidWithParent(tag: string, parentTag: ?string): boolean {
tag === 'hr' ||
tag === 'option' ||
tag === 'optgroup' ||
tag === 'script' ||
tag === 'template' ||
tag === '#text'
);
case 'optgroup':
Expand Down
6 changes: 1 addition & 5 deletions packages/react-reconciler/src/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ import {
DidDefer,
} from './ReactFiberFlags';
import {
debugRenderPhaseSideEffectsForStrictMode,
disableLegacyContext,
disableLegacyContextForFunctionComponents,
enableProfilerCommitHooks,
Expand Down Expand Up @@ -1375,10 +1374,7 @@ function finishClassComponent(
}
if (__DEV__) {
nextChildren = callRenderInDEV(instance);
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictLegacyMode
) {
if (workInProgress.mode & StrictLegacyMode) {
setIsStrictModeForDevtools(true);
try {
callRenderInDEV(instance);
Expand Down
16 changes: 3 additions & 13 deletions packages/react-reconciler/src/ReactFiberClassComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
MountLayoutDev,
} from './ReactFiberFlags';
import {
debugRenderPhaseSideEffectsForStrictMode,
disableLegacyContext,
enableSchedulingProfiler,
disableDefaultPropsExceptForClasses,
Expand Down Expand Up @@ -138,10 +137,7 @@ function applyDerivedStateFromProps(
const prevState = workInProgress.memoizedState;
let partialState = getDerivedStateFromProps(nextProps, prevState);
if (__DEV__) {
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictLegacyMode
) {
if (workInProgress.mode & StrictLegacyMode) {
setIsStrictModeForDevtools(true);
try {
// Invoke the function an extra time to help detect side-effects.
Expand Down Expand Up @@ -266,10 +262,7 @@ function checkShouldComponentUpdate(
nextContext,
);
if (__DEV__) {
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictLegacyMode
) {
if (workInProgress.mode & StrictLegacyMode) {
setIsStrictModeForDevtools(true);
try {
// Invoke the function an extra time to help detect side-effects.
Expand Down Expand Up @@ -598,10 +591,7 @@ function constructClassInstance(
let instance = new ctor(props, context);
// Instantiate twice to help detect side-effects.
if (__DEV__) {
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictLegacyMode
) {
if (workInProgress.mode & StrictLegacyMode) {
setIsStrictModeForDevtools(true);
try {
instance = new ctor(props, context);
Expand Down
12 changes: 2 additions & 10 deletions packages/react-reconciler/src/ReactFiberClassUpdateQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,6 @@ import {
} from './ReactFiberFlags';
import getComponentNameFromFiber from './getComponentNameFromFiber';

import {debugRenderPhaseSideEffectsForStrictMode} from 'shared/ReactFeatureFlags';

import {StrictLegacyMode} from './ReactTypeOfMode';
import {
markSkippedUpdateLanes,
Expand Down Expand Up @@ -402,10 +400,7 @@ function getStateFromUpdate<State>(
}
const nextState = payload.call(instance, prevState, nextProps);
if (__DEV__) {
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictLegacyMode
) {
if (workInProgress.mode & StrictLegacyMode) {
setIsStrictModeForDevtools(true);
try {
payload.call(instance, prevState, nextProps);
Expand Down Expand Up @@ -435,10 +430,7 @@ function getStateFromUpdate<State>(
}
partialState = payload.call(instance, prevState, nextProps);
if (__DEV__) {
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictLegacyMode
) {
if (workInProgress.mode & StrictLegacyMode) {
setIsStrictModeForDevtools(true);
try {
payload.call(instance, prevState, nextProps);
Expand Down
5 changes: 1 addition & 4 deletions packages/react-reconciler/src/ReactFiberHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import {
enableUseEffectEventHook,
enableUseResourceEffectHook,
enableLegacyCache,
debugRenderPhaseSideEffectsForStrictMode,
disableLegacyMode,
enableNoCloningMemoCache,
} from 'shared/ReactFeatureFlags';
Expand Down Expand Up @@ -623,9 +622,7 @@ export function renderWithHooks<Props, SecondArg>(
//
// There are plenty of tests to ensure this behavior is correct.
const shouldDoubleRenderDEV =
__DEV__ &&
debugRenderPhaseSideEffectsForStrictMode &&
(workInProgress.mode & StrictLegacyMode) !== NoMode;
__DEV__ && (workInProgress.mode & StrictLegacyMode) !== NoMode;

shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV;
let children = __DEV__
Expand Down
3 changes: 1 addition & 2 deletions packages/react-reconciler/src/ReactFiberWorkLoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
enableSchedulingProfiler,
enableUpdaterTracking,
enableTransitionTracing,
useModernStrictMode,
disableLegacyContext,
alwaysThrottleRetries,
enableInfiniteRenderLoopDetection,
Expand Down Expand Up @@ -4205,7 +4204,7 @@ function commitDoubleInvokeEffectsInDEV(
hasPassiveEffects: boolean,
) {
if (__DEV__) {
if (useModernStrictMode && (disableLegacyMode || root.tag !== LegacyRoot)) {
if (disableLegacyMode || root.tag !== LegacyRoot) {
let doubleInvokeEffects = true;

if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('Activity StrictMode', () => {
]);
});

// @gate __DEV__ && enableActivity && useModernStrictMode
// @gate __DEV__ && enableActivity
it('should not trigger strict effects when offscreen is hidden', async () => {
await act(() => {
ReactNoop.render(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
'use strict';

let React;
let ReactFeatureFlags;
let ReactTestRenderer;
let Scheduler;
let ReactDOMServer;
Expand All @@ -26,8 +25,6 @@ let waitForThrow;
describe('ReactHooks', () => {
beforeEach(() => {
jest.resetModules();
ReactFeatureFlags = require('shared/ReactFeatureFlags');

React = require('react');
ReactTestRenderer = require('react-test-renderer');
Scheduler = require('scheduler');
Expand Down Expand Up @@ -1240,8 +1237,6 @@ describe('ReactHooks', () => {
});

it('double-invokes components with Hooks in Strict Mode', async () => {
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = true;

const {useState, StrictMode} = React;
let renderCount = 0;

Expand Down Expand Up @@ -1459,7 +1454,6 @@ describe('ReactHooks', () => {
});

it('double-invokes useMemo in DEV StrictMode despite []', async () => {
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = true;
const {useMemo, StrictMode} = React;

let useMemoCount = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ describe('updaters', () => {

ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableUpdaterTracking = true;
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;

mockDevToolsHook = {
injectInternals: jest.fn(() => {}),
Expand Down
49 changes: 20 additions & 29 deletions packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -945,34 +945,25 @@ describe('StrictEffectsMode', () => {
shouldSuspend = false;
});

if (gate(flags => flags.useModernStrictMode)) {
expect(log).toEqual([
'Child rendered',
'Child rendered',
// !!! Committed, destroy and create effect.
// !!! The other effect is not destroyed and created
// !!! because the dep didn't change
'Child dep destroy',
'Child dep create',

// Double invoke both effects
'Child destroy',
'Child dep destroy',
'Child create',
'Child dep create',
// Fires setState
'-----------------------after setState',
'Child rendered',
'Child rendered',
'Child dep create',
]);
} else {
expect(log).toEqual([
'Child rendered',
'Child rendered',
'Child dep destroy',
'Child dep create',
]);
}
expect(log).toEqual([
'Child rendered',
'Child rendered',
// !!! Committed, destroy and create effect.
// !!! The other effect is not destroyed and created
// !!! because the dep didn't change
'Child dep destroy',
'Child dep create',

// Double invoke both effects
'Child destroy',
'Child dep destroy',
'Child create',
'Child dep create',
// Fires setState
'-----------------------after setState',
'Child rendered',
'Child rendered',
'Child dep create',
]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,6 @@ describe('StrictEffectsMode defaults', () => {
expect(log).toEqual([]);
});

//@gate useModernStrictMode
it('disconnects refs during double invoking', async () => {
const onRefMock = jest.fn();
function App({text}) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ describe('useRef', () => {
ReactNoop = require('react-noop-renderer');
Scheduler = require('scheduler');

const ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;

act = require('internal-test-utils').act;
useCallback = React.useCallback;
useEffect = React.useEffect;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,31 @@ describe('ReactFlightDOMReplyEdge', () => {
),
);
});

it('should abort when parsing an incomplete payload', async () => {
const infinitePromise = new Promise(() => {});
const controller = new AbortController();
const promiseForResult = ReactServerDOMClient.encodeReply(
{promise: infinitePromise},
{
signal: controller.signal,
},
);
controller.abort();
const body = await promiseForResult;

const decoded = await ReactServerDOMServer.decodeReply(
body,
webpackServerMap,
);

let error = null;
try {
await decoded.promise;
} catch (x) {
error = x;
}
expect(error).not.toBe(null);
expect(error.message).toBe('Connection closed.');
});
});
18 changes: 18 additions & 0 deletions packages/react-server/src/ReactFlightReplyServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ export type Response = {
_prefix: string,
_formData: FormData,
_chunks: Map<number, SomeChunk<any>>,
_closed: boolean,
_closedReason: mixed,
_temporaryReferences: void | TemporaryReferenceSet,
};

Expand Down Expand Up @@ -255,6 +257,14 @@ function createResolvedModelChunk<T>(
return new Chunk(RESOLVED_MODEL, value, id, response);
}

function createErroredChunk<T>(
response: Response,
reason: mixed,
): ErroredChunk<T> {
// $FlowFixMe[invalid-constructor] Flow doesn't support functions as constructors
return new Chunk(ERRORED, null, reason, response);
}

function resolveModelChunk<T>(
chunk: SomeChunk<T>,
value: string,
Expand Down Expand Up @@ -493,6 +503,8 @@ function initializeModelChunk<T>(chunk: ResolvedModelChunk<T>): void {
// Report that any missing chunks in the model is now going to throw this
// error upon read. Also notify any pending promises.
export function reportGlobalError(response: Response, error: Error): void {
response._closed = true;
response._closedReason = error;
response._chunks.forEach(chunk => {
// If this chunk was already resolved or errored, it won't
// trigger an error but if it wasn't then we need to
Expand All @@ -514,6 +526,10 @@ function getChunk(response: Response, id: number): SomeChunk<any> {
if (backingEntry != null) {
// We assume that this is a string entry for now.
chunk = createResolvedModelChunk(response, (backingEntry: any), id);
} else if (response._closed) {
// We have already errored the response and we're not going to get
// anything more streaming in so this will immediately error.
chunk = createErroredChunk(response, response._closedReason);
} else {
// We're still waiting on this entry to stream in.
chunk = createPendingChunk(response);
Expand Down Expand Up @@ -1082,6 +1098,8 @@ export function createResponse(
_prefix: formFieldPrefix,
_formData: backingFormData,
_chunks: chunks,
_closed: false,
_closedReason: null,
_temporaryReferences: temporaryReferences,
};
return response;
Expand Down
10 changes: 5 additions & 5 deletions packages/react/src/__tests__/ReactStrictMode-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ describe('ReactStrictMode', () => {
expect(instance.state.count).toBe(2);
});

// @gate debugRenderPhaseSideEffectsForStrictMode
// @gate __DEV__
it('double invokes useState and useReducer initializers functions', async () => {
const log = [];

Expand Down Expand Up @@ -390,7 +390,7 @@ describe('ReactStrictMode', () => {
expect(instance.state.count).toBe(2);
});

// @gate debugRenderPhaseSideEffectsForStrictMode
// @gate __DEV__
it('double invokes useMemo functions', async () => {
let log = [];

Expand Down Expand Up @@ -436,7 +436,7 @@ describe('ReactStrictMode', () => {
]);
});

// @gate debugRenderPhaseSideEffectsForStrictMode
// @gate __DEV__
it('double invokes useMemo functions with first result', async () => {
let log = [];
function Uppercased({text}) {
Expand Down Expand Up @@ -499,7 +499,7 @@ describe('ReactStrictMode', () => {
expect(log[2]).toBe(log[3]);
});

// @gate debugRenderPhaseSideEffectsForStrictMode
// @gate __DEV__
it('double invokes setState updater functions', async () => {
const log = [];

Expand Down Expand Up @@ -532,7 +532,7 @@ describe('ReactStrictMode', () => {
expect(log).toEqual(['Compute count: 1', 'Compute count: 1']);
});

// @gate debugRenderPhaseSideEffectsForStrictMode
// @gate __DEV__
it('double invokes reducer functions', async () => {
const log = [];

Expand Down
Loading
Loading