From 15fa278c571153f474c91b065204223d2cc31e68 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Tue, 29 Sep 2026 07:06:31 +0200 Subject: [PATCH 1/6] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75588=20fix:?= =?UTF-8?q?=20react-reconciler@0.33=20by=20@mdjastrzebski?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/react-reconciler/index.d.ts | 378 +++++++++++++--- .../ReactFiberHostConfigWithNoHydration.ts | 25 +- .../test/ReactTestHostConfig.ts | 62 ++- .../test/react-reconciler-tests.ts | 403 +++++++++++++++++- 4 files changed, 769 insertions(+), 99 deletions(-) diff --git a/types/react-reconciler/index.d.ts b/types/react-reconciler/index.d.ts index c0762387a68005..20cf4f1c01097f 100644 --- a/types/react-reconciler/index.d.ts +++ b/types/react-reconciler/index.d.ts @@ -7,6 +7,7 @@ declare function ReactReconciler< Container, Instance, TextInstance, + ActivityInstance, SuspenseInstance, HydratableInstance, FormInstance, @@ -16,6 +17,11 @@ declare function ReactReconciler< TimeoutHandle, NoTimeout, TransitionStatus, + SuspendedState, + RendererInspectionConfig, + FormStateMarkerInstance, + HoistableRoot, + Resource, >( /* eslint-enable @definitelytyped/no-unnecessary-generics */ config: ReactReconciler.HostConfig< @@ -24,6 +30,7 @@ declare function ReactReconciler< Container, Instance, TextInstance, + ActivityInstance, SuspenseInstance, HydratableInstance, FormInstance, @@ -32,7 +39,12 @@ declare function ReactReconciler< ChildSet, TimeoutHandle, NoTimeout, - TransitionStatus + TransitionStatus, + SuspendedState, + RendererInspectionConfig, + FormStateMarkerInstance, + HoistableRoot, + Resource >, ): ReactReconciler.Reconciler; @@ -43,6 +55,7 @@ declare namespace ReactReconciler { Container, Instance, TextInstance, + ActivityInstance, SuspenseInstance, HydratableInstance, FormInstance, @@ -52,6 +65,11 @@ declare namespace ReactReconciler { TimeoutHandle, NoTimeout, TransitionStatus, + SuspendedState, + RendererInspectionConfig, + FormStateMarkerInstance, + HoistableRoot, + Resource, > { // ------------------- // Modes @@ -94,6 +112,30 @@ declare namespace ReactReconciler { */ supportsPersistence: boolean; + // ------------------- + // Renderer metadata + // ------------------- + + /** + * The version of your renderer. React DevTools reports this alongside the reconciler version, which may differ for third-party renderers. + */ + rendererVersion: string; + + /** + * The npm package name of your renderer, reported to React DevTools. + */ + rendererPackageName: string; + + /** + * Extra renderer-specific configuration exposed to React DevTools as `rendererConfig`. Return `null` if you have nothing to expose. + */ + extraDevToolsConfig: RendererInspectionConfig | null; + + /** + * Binds a `console` method call (as captured by React's replaying of Server console logs on the client) so it can be invoked later, optionally tagging it with an environment name badge. + */ + bindToConsole(methodName: string, args: any[], badgeName: string): () => any; + // ------------------- // Core Methods // ------------------- @@ -180,7 +222,7 @@ declare namespace ReactReconciler { * * This method happens **in the render phase**. Do not mutate the tree from it. */ - getChildHostContext(parentHostContext: HostContext, type: Type, rootContainer: Container): HostContext; + getChildHostContext(parentHostContext: HostContext, type: Type): HostContext; /** * Determines what object gets exposed as a ref. You'll likely want to return the `instance` itself. But in some cases it might make sense to only expose some part of it. @@ -404,11 +446,25 @@ declare namespace ReactReconciler { // ------------------- supportsHydration: boolean; - canHydrateInstance?(instance: HydratableInstance, type: Type, props: Props): null | Instance; + canHydrateInstance?( + instance: HydratableInstance, + type: Type, + props: Props, + inRootOrSingleton: boolean, + ): null | Instance; + + canHydrateTextInstance?( + instance: HydratableInstance, + text: string, + inRootOrSingleton: boolean, + ): null | TextInstance; - canHydrateTextInstance?(instance: HydratableInstance, text: string): null | TextInstance; + canHydrateActivityInstance?( + instance: HydratableInstance, + inRootOrSingleton: boolean, + ): null | ActivityInstance; - canHydrateSuspenseInstance?(instance: HydratableInstance): null | SuspenseInstance; + canHydrateSuspenseInstance?(instance: HydratableInstance, inRootOrSingleton: boolean): null | SuspenseInstance; isSuspenseInstancePending?(instance: SuspenseInstance): boolean; @@ -424,73 +480,111 @@ declare namespace ReactReconciler { instance: Instance, type: Type, props: Props, - rootContainerInstance: Container, hostContext: HostContext, internalInstanceHandle: any, - ): null | any[]; + ): boolean; - hydrateTextInstance?(textInstance: TextInstance, text: string, internalInstanceHandle: any): boolean; + hydrateTextInstance?( + textInstance: TextInstance, + text: string, + internalInstanceHandle: any, + parentProps: null | Props, + ): boolean; + + hydrateActivityInstance?(activityInstance: ActivityInstance, internalInstanceHandle: any): void; hydrateSuspenseInstance?(suspenseInstance: SuspenseInstance, internalInstanceHandle: any): void; - getNextHydratableInstanceAfterSuspenseInstance?(suspenseInstance: SuspenseInstance): null | HydratableInstance; + getNextHydratableInstanceAfterActivityInstance?(activityInstance: ActivityInstance): null | HydratableInstance; - // Returns the SuspenseInstance if this node is a direct child of a - // SuspenseInstance. I.e. if its previous sibling is a Comment with - // SUSPENSE_x_START_DATA. Otherwise, null. - getParentSuspenseInstance?(targetInstance: any): null | SuspenseInstance; + getNextHydratableInstanceAfterSuspenseInstance?(suspenseInstance: SuspenseInstance): null | HydratableInstance; commitHydratedContainer?(container: Container): void; - commitHydratedSuspenseInstance?(suspenseInstance: SuspenseInstance): void; + commitHydratedInstance?(instance: Instance, type: Type, props: Props, internalHandle: OpaqueHandle): void; - didNotMatchHydratedContainerTextInstance?( - parentContainer: Container, - textInstance: TextInstance, - text: string, - ): void; + commitHydratedActivityInstance?(activityInstance: ActivityInstance): void; - didNotMatchHydratedTextInstance?( - parentType: Type, - parentProps: Props, - parentInstance: Instance, - textInstance: TextInstance, - text: string, - ): void; + finalizeHydratedChildren?( + instance: Instance, + type: Type, + props: Props, + hostContext: HostContext, + ): boolean; - didNotHydrateContainerInstance?(parentContainer: Container, instance: HydratableInstance): void; + flushHydrationEvents?(): void; - didNotHydrateInstance?( - parentType: Type, - parentProps: Props, - parentInstance: Instance, - instance: HydratableInstance, - ): void; + clearActivityBoundary?(parentInstance: Instance, activityInstance: ActivityInstance): void; - didNotFindHydratableContainerInstance?(parentContainer: Container, type: Type, props: Props): void; + clearSuspenseBoundary?(parentInstance: Instance, suspenseInstance: SuspenseInstance): void; - didNotFindHydratableContainerTextInstance?(parentContainer: Container, text: string): void; + clearActivityBoundaryFromContainer?(container: Container, activityInstance: ActivityInstance): void; - didNotFindHydratableContainerSuspenseInstance?(parentContainer: Container): void; + clearSuspenseBoundaryFromContainer?(container: Container, suspenseInstance: SuspenseInstance): void; - didNotFindHydratableInstance?( - parentType: Type, - parentProps: Props, - parentInstance: Instance, + hideDehydratedBoundary?(suspenseInstance: SuspenseInstance): void; + + unhideDehydratedBoundary?(dehydratedInstance: SuspenseInstance | ActivityInstance): void; + + shouldDeleteUnhydratedTailInstances?(parentType: Type): boolean; + + getFirstHydratableChildWithinContainer?(parentContainer: Container): HydratableInstance | null; + + getFirstHydratableChildWithinActivityInstance?( + parentInstance: ActivityInstance, + ): HydratableInstance | null; + + getFirstHydratableChildWithinSuspenseInstance?( + parentInstance: SuspenseInstance, + ): HydratableInstance | null; + + getFirstHydratableChildWithinSingleton?( + type: Type, + singletonInstance: Instance, + currentHydratableInstance: HydratableInstance | null, + ): HydratableInstance | null; + + getNextHydratableSiblingAfterSingleton?( + type: Type, + currentHydratableInstance: HydratableInstance | null, + ): HydratableInstance | null; + + getSuspenseInstanceFallbackErrorDetails?( + instance: SuspenseInstance, + ): SuspenseInstanceFallbackErrorDetails; + + canHydrateFormStateMarker?( + instance: HydratableInstance, + inRootOrSingleton: boolean, + ): FormStateMarkerInstance | null; + + isFormStateMarkerMatching?(markerInstance: FormStateMarkerInstance): boolean; + + /** + * Replaces the removed `didNotMatchHydrated*` / `didNotFindHydratable*` dev warnings. + */ + diffHydratedPropsForDevWarnings?( + instance: Instance, type: Type, props: Props, - ): void; + hostContext: HostContext, + ): Props | null; - didNotFindHydratableTextInstance?( - parentType: Type, - parentProps: Props, - parentInstance: Instance, + diffHydratedTextForDevWarnings?( + textInstance: TextInstance, text: string, - ): void; + parentProps: Props | null, + ): string | null; + + describeHydratableInstanceForDevWarnings?( + instance: HydratableInstance, + ): string | HydratableInstanceDescription; + + validateHydratableInstance?(type: Type, props: Props, hostContext: HostContext): boolean; - didNotFindHydratableSuspenseInstance?(parentType: Type, parentProps: Props, parentInstance: Instance): void; + validateHydratableTextInstance?(text: string, hostContext: HostContext): boolean; - errorHydratingContainer?(parentContainer: Container): void; + commitHydratedSuspenseInstance?(suspenseInstance: SuspenseInstance): void; // Undocumented // https://github.com/facebook/react/pull/26722 @@ -523,20 +617,35 @@ declare namespace ReactReconciler { */ maySuspendCommit(type: Type, props: Props): boolean; + /** + * Same as `maySuspendCommit`, but called for an update to an existing instance instead of its initial mount, so it receives both the old and new props. + */ + maySuspendCommitOnUpdate(type: Type, oldProps: Props, newProps: Props): boolean; + + /** + * This method is called during a sync render to determine if the Host Component type and props are still allowed to suspend the commit. Host configs that don't want to suspend sync commits should always return `false`. + */ + maySuspendCommitInSyncRender(type: Type, props: Props): boolean; + /** * This method may be called during render if the Host Component type and props might suspend a commit. It can be used to initiate any work that might shorten the duration of a suspended commit. */ - preloadInstance(type: Type, props: Props): boolean; + preloadInstance(instance: Instance, type: Type, props: Props): boolean; /** * This method is called just before the commit phase. Use it to set up any necessary state while any Host Components that might suspend this commit are evaluated to determine if the commit must be suspended. */ - startSuspendingCommit(): void; + startSuspendingCommit(): SuspendedState; /** * This method is called after `startSuspendingCommit` for each Host Component that indicated it might suspend a commit. */ - suspendInstance(type: Type, props: Props): void; + suspendInstance(state: SuspendedState, instance: Instance, type: Type, props: Props): void; + + /** + * This method is called after `startSuspendingCommit` if there is a View Transition currently active on the root that the commit should wait to finish before proceeding. + */ + suspendOnActiveViewTransition(state: SuspendedState, rootContainer: Container): void; /** * This method is called after all `suspendInstance` calls are complete. @@ -545,9 +654,136 @@ declare namespace ReactReconciler { * * Return `(initiateCommit: Function) => Function` if the commit must be suspended. The argument to this callback will initiate the commit when called. The return value is a cancellation function that the Reconciler can use to abort the commit. */ - waitForCommitToBeReady(): + waitForCommitToBeReady( + state: SuspendedState, + timeoutOffset: number, + ): | ((initiateCommit: (...args: unknown[]) => unknown) => (...args: unknown[]) => unknown) | null; + + /** + * This method is called when a commit is suspended, to record why. It is only called when the profiler is enabled, and the result is attached to the pending commit. Return `null` if there's nothing to report. + */ + getSuspendedCommitReason(state: SuspendedState, rootContainer: Container): null | string; + + // ------------------- + // Resources + // (optional) + // ------------------- + /** + * Set this to `true` if your renderer supports Resources, e.g. hoistable ``/`