From fa7c1dd76acb25a7876a87902950f2feced73f6e Mon Sep 17 00:00:00 2001 From: eps1lon Date: Wed, 3 Apr 2024 14:22:01 +0200 Subject: [PATCH] [Devtools] Ensure initial read of useFormStatus returns NotPendingTransition --- packages/react-art/src/ReactFiberConfigART.js | 13 ++++++++ ...ReactHooksInspectionIntegrationDOM-test.js | 7 ++++- .../src/client/ReactFiberConfigDOM.js | 12 ++++++- .../src/ReactFiberConfigFabric.js | 10 ++++++ .../src/ReactFiberConfigNative.js | 11 +++++++ .../src/ReactFiberBeginWork.js | 2 +- .../react-reconciler/src/ReactFiberHooks.js | 5 ++- .../src/ReactFiberHostContext.js | 31 ++++--------------- .../src/ReactFiberNewContext.js | 7 ++--- .../src/forks/ReactFiberConfig.custom.js | 1 + .../src/ReactFiberConfigTestHost.js | 11 +++++++ 11 files changed, 74 insertions(+), 36 deletions(-) diff --git a/packages/react-art/src/ReactFiberConfigART.js b/packages/react-art/src/ReactFiberConfigART.js index 1fee29d43dad0..39fd42c3fa460 100644 --- a/packages/react-art/src/ReactFiberConfigART.js +++ b/packages/react-art/src/ReactFiberConfigART.js @@ -17,6 +17,9 @@ import { NoEventPriority, } from 'react-reconciler/src/ReactEventPriorities'; +import type {ReactContext} from 'shared/ReactTypes'; +import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols'; + const pooledTransform = new Transform(); const NO_CONTEXT = {}; @@ -24,6 +27,8 @@ if (__DEV__) { Object.freeze(NO_CONTEXT); } +export type TransitionStatus = mixed; + /** Helper Methods */ function addEventListeners(instance, type, listener) { @@ -490,4 +495,12 @@ export function waitForCommitToBeReady() { } export const NotPendingTransition = null; +export const HostTransitionContext: ReactContext = { + $$typeof: REACT_CONTEXT_TYPE, + Provider: (null: any), + Consumer: (null: any), + _currentValue: NotPendingTransition, + _currentValue2: NotPendingTransition, + _threadCount: 0, +}; export function resetFormInstance() {} diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegrationDOM-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegrationDOM-test.js index 752d93fa30ab8..3ef3c2f3a7b7b 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegrationDOM-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegrationDOM-test.js @@ -119,7 +119,12 @@ describe('ReactHooksInspectionIntegration', () => { isStateEditable: false, name: 'FormStatus', subHooks: [], - value: null, + value: { + action: null, + data: null, + method: null, + pending: false, + }, }, { debugInfo: null, diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 9e937c013829c..874febf8c6f6e 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -9,12 +9,13 @@ import type {DOMEventName} from '../events/DOMEventNames'; import type {Fiber, FiberRoot} from 'react-reconciler/src/ReactInternalTypes'; + import type { BoundingRect, IntersectionObserverOptions, ObserveVisibleRectsCallback, } from 'react-reconciler/src/ReactTestSelectors'; -import type {ReactScopeInstance} from 'shared/ReactTypes'; +import type {ReactContext, ReactScopeInstance} from 'shared/ReactTypes'; import type {AncestorInfoDev} from './validateDOMNesting'; import type {FormStatus} from 'react-dom-bindings/src/shared/ReactDOMFormActions'; import type { @@ -31,6 +32,7 @@ import {getCurrentRootHostContainer} from 'react-reconciler/src/ReactFiberHostCo import hasOwnProperty from 'shared/hasOwnProperty'; import {checkAttributeStringCoercion} from 'shared/CheckStringCoercion'; +import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols'; export { setCurrentUpdatePriority, @@ -3460,6 +3462,14 @@ function insertStylesheetIntoRoot( } export const NotPendingTransition: TransitionStatus = NotPending; +export const HostTransitionContext: ReactContext = { + $$typeof: REACT_CONTEXT_TYPE, + Provider: (null: any), + Consumer: (null: any), + _currentValue: NotPendingTransition, + _currentValue2: NotPendingTransition, + _threadCount: 0, +}; export type FormInstance = HTMLFormElement; export function resetFormInstance(form: FormInstance): void { diff --git a/packages/react-native-renderer/src/ReactFiberConfigFabric.js b/packages/react-native-renderer/src/ReactFiberConfigFabric.js index f1b6859ab7ea2..22958225c7a98 100644 --- a/packages/react-native-renderer/src/ReactFiberConfigFabric.js +++ b/packages/react-native-renderer/src/ReactFiberConfigFabric.js @@ -49,6 +49,8 @@ const { } = nativeFabricUIManager; import {passChildrenWhenCloningPersistedNodes} from 'shared/ReactFeatureFlags'; +import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols'; +import type {ReactContext} from 'shared/ReactTypes'; const {get: getViewConfigForType} = ReactNativeViewConfigRegistry; @@ -514,6 +516,14 @@ export function waitForCommitToBeReady(): null { } export const NotPendingTransition: TransitionStatus = null; +export const HostTransitionContext: ReactContext = { + $$typeof: REACT_CONTEXT_TYPE, + Provider: (null: any), + Consumer: (null: any), + _currentValue: NotPendingTransition, + _currentValue2: NotPendingTransition, + _threadCount: 0, +}; export type FormInstance = Instance; export function resetFormInstance(form: Instance): void {} diff --git a/packages/react-native-renderer/src/ReactFiberConfigNative.js b/packages/react-native-renderer/src/ReactFiberConfigNative.js index 20a3f150fd111..a3c1df9dfb6cb 100644 --- a/packages/react-native-renderer/src/ReactFiberConfigNative.js +++ b/packages/react-native-renderer/src/ReactFiberConfigNative.js @@ -31,6 +31,9 @@ import { } from 'react-reconciler/src/ReactEventPriorities'; import type {Fiber} from 'react-reconciler/src/ReactInternalTypes'; +import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols'; +import type {ReactContext} from 'shared/ReactTypes'; + const {get: getViewConfigForType} = ReactNativeViewConfigRegistry; export type Type = string; @@ -549,6 +552,14 @@ export function waitForCommitToBeReady(): null { } export const NotPendingTransition: TransitionStatus = null; +export const HostTransitionContext: ReactContext = { + $$typeof: REACT_CONTEXT_TYPE, + Provider: (null: any), + Consumer: (null: any), + _currentValue: NotPendingTransition, + _currentValue2: NotPendingTransition, + _threadCount: 0, +}; export type FormInstance = Instance; export function resetFormInstance(form: Instance): void {} diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 034c853976aa8..942cd9be5785e 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -176,6 +176,7 @@ import { isPrimaryRenderer, getResource, createHoistableInstance, + HostTransitionContext, } from './ReactFiberConfig'; import type {SuspenseInstance} from './ReactFiberConfig'; import {shouldError, shouldSuspend} from './ReactFiberReconciler'; @@ -183,7 +184,6 @@ import { pushHostContext, pushHostContainer, getRootHostContainer, - HostTransitionContext, } from './ReactFiberHostContext'; import { suspenseStackCursor, diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js index cb5aec4fb4e2c..ad1a2d9d035d4 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.js +++ b/packages/react-reconciler/src/ReactFiberHooks.js @@ -28,6 +28,7 @@ import type {Flags} from './ReactFiberFlags'; import type {TransitionStatus} from './ReactFiberConfig'; import { + HostTransitionContext, NotPendingTransition as NoPendingHostTransition, setCurrentUpdatePriority, getCurrentUpdatePriority, @@ -150,7 +151,6 @@ import { peekEntangledActionThenable, chainThenableValue, } from './ReactFiberAsyncAction'; -import {HostTransitionContext} from './ReactFiberHostContext'; import {requestTransitionLane} from './ReactFiberRootScheduler'; import {isCurrentTreeHidden} from './ReactFiberHiddenContext'; import { @@ -3100,8 +3100,7 @@ function useHostTransitionStatus(): TransitionStatus { if (!enableAsyncActions) { throw new Error('Not implemented.'); } - const status: TransitionStatus | null = readContext(HostTransitionContext); - return status !== null ? status : NoPendingHostTransition; + return readContext(HostTransitionContext); } function mountId(): string { diff --git a/packages/react-reconciler/src/ReactFiberHostContext.js b/packages/react-reconciler/src/ReactFiberHostContext.js index f930799f56387..51a4307feddfb 100644 --- a/packages/react-reconciler/src/ReactFiberHostContext.js +++ b/packages/react-reconciler/src/ReactFiberHostContext.js @@ -9,21 +9,17 @@ import type {Fiber} from './ReactInternalTypes'; import type {StackCursor} from './ReactFiberStack'; -import type { - Container, - HostContext, - TransitionStatus, -} from './ReactFiberConfig'; +import type {Container, HostContext} from './ReactFiberConfig'; import type {Hook} from './ReactFiberHooks'; -import type {ReactContext} from 'shared/ReactTypes'; import { getChildHostContext, getRootHostContext, + HostTransitionContext, + NotPendingTransition, isPrimaryRenderer, } from './ReactFiberConfig'; import {createCursor, push, pop} from './ReactFiberStack'; -import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols'; import {enableAsyncActions} from 'shared/ReactFeatureFlags'; const contextStackCursor: StackCursor = createCursor(null); @@ -38,21 +34,6 @@ const rootInstanceStackCursor: StackCursor = const hostTransitionProviderCursor: StackCursor = createCursor(null); -// TODO: This should initialize to NotPendingTransition, a constant -// imported from the fiber config. However, because of a cycle in the module -// graph, that value isn't defined during this module's initialization. I can't -// think of a way to work around this without moving that value out of the -// fiber config. For now, the "no provider" case is handled when reading, -// inside useHostTransitionStatus. -export const HostTransitionContext: ReactContext = { - $$typeof: REACT_CONTEXT_TYPE, - Provider: (null: any), - Consumer: (null: any), - _currentValue: null, - _currentValue2: null, - _threadCount: 0, -}; - function requiredContext(c: Value | null): Value { if (__DEV__) { if (c === null) { @@ -150,13 +131,13 @@ function popHostContext(fiber: Fiber): void { pop(hostTransitionProviderCursor, fiber); // When popping the transition provider, we reset the context value back - // to `null`. We can do this because you're not allowd to nest forms. If + // to `NotPendingTransition`. We can do this because you're not allowd to nest forms. If // we allowed for multiple nested host transition providers, then we'd // need to reset this to the parent provider's status. if (isPrimaryRenderer) { - HostTransitionContext._currentValue = null; + HostTransitionContext._currentValue = NotPendingTransition; } else { - HostTransitionContext._currentValue2 = null; + HostTransitionContext._currentValue2 = NotPendingTransition; } } } diff --git a/packages/react-reconciler/src/ReactFiberNewContext.js b/packages/react-reconciler/src/ReactFiberNewContext.js index c19e056b0a3cd..aa250302d3130 100644 --- a/packages/react-reconciler/src/ReactFiberNewContext.js +++ b/packages/react-reconciler/src/ReactFiberNewContext.js @@ -19,7 +19,7 @@ import type {SharedQueue} from './ReactFiberClassUpdateQueue'; import type {TransitionStatus} from './ReactFiberConfig'; import type {Hook} from './ReactFiberHooks'; -import {isPrimaryRenderer} from './ReactFiberConfig'; +import {isPrimaryRenderer, HostTransitionContext} from './ReactFiberConfig'; import {createCursor, push, pop} from './ReactFiberStack'; import { ContextProvider, @@ -47,10 +47,7 @@ import { enableAsyncActions, enableRenderableContext, } from 'shared/ReactFeatureFlags'; -import { - getHostTransitionProvider, - HostTransitionContext, -} from './ReactFiberHostContext'; +import {getHostTransitionProvider} from './ReactFiberHostContext'; const valueCursor: StackCursor = createCursor(null); diff --git a/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js b/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js index 7ba17939736de..eb777c0a7990e 100644 --- a/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js +++ b/packages/react-reconciler/src/forks/ReactFiberConfig.custom.js @@ -79,6 +79,7 @@ export const startSuspendingCommit = $$$config.startSuspendingCommit; export const suspendInstance = $$$config.suspendInstance; export const waitForCommitToBeReady = $$$config.waitForCommitToBeReady; export const NotPendingTransition = $$$config.NotPendingTransition; +export const HostTransitionContext = $$$config.HostTransitionContext; export const resetFormInstance = $$$config.resetFormInstance; // ------------------- diff --git a/packages/react-test-renderer/src/ReactFiberConfigTestHost.js b/packages/react-test-renderer/src/ReactFiberConfigTestHost.js index c9474a8950dde..f6d4fb4d91af0 100644 --- a/packages/react-test-renderer/src/ReactFiberConfigTestHost.js +++ b/packages/react-test-renderer/src/ReactFiberConfigTestHost.js @@ -7,7 +7,10 @@ * @flow */ +import type {ReactContext} from 'shared/ReactTypes'; + import isArray from 'shared/isArray'; +import {REACT_CONTEXT_TYPE} from 'shared/ReactSymbols'; import { DefaultEventPriority, NoEventPriority, @@ -349,6 +352,14 @@ export function waitForCommitToBeReady(): null { } export const NotPendingTransition: TransitionStatus = null; +export const HostTransitionContext: ReactContext = { + $$typeof: REACT_CONTEXT_TYPE, + Provider: (null: any), + Consumer: (null: any), + _currentValue: NotPendingTransition, + _currentValue2: NotPendingTransition, + _threadCount: 0, +}; export type FormInstance = Instance; export function resetFormInstance(form: Instance): void {}