Files
react/packages/shared/ReactTypes.js
Sebastian Markbåge 19bd26beb6 [Flight/DevTools] Pass the Server Component's "key" as Part of the ReactComponentInfo (#30703)
Supports showing the key in DevTools on the Server Component that the
key was applied to. We can also use this to reconcile to preserve
instance equality when they're reordered.

One thing that's a bit weird about this is that if you provide an
explicit key on a Server Component that alone doesn't have any
semantics. It's because we pass the key down and let the nearest child
inherit the key or get prefixed by the key.

So you might see the same key as a prefix on the child of the Server
Component too which might be a bit confusing. We could remove the prefix
from children but that might also be a bit confusing if they collide.

The div in this case doesn't have a key explicitly specified. It gets it
from the Server Component parent.

<img width="1107" alt="Screenshot 2024-08-14 at 10 06 36 PM"
src="https://github.com/user-attachments/assets/cfc517cc-e737-44c3-a1be-050049267ee2">

Overall keys get a bit confusing when you apply filter. Especially since
it's so common to actually apply the key on a Host Instance. So you
often don't see the key.
2024-08-15 11:04:53 -04:00

208 lines
5.3 KiB
JavaScript

/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export type ReactNode =
| React$Element<any>
| ReactPortal
| ReactText
| ReactFragment
| ReactProvider<any>
| ReactConsumer<any>;
export type ReactEmpty = null | void | boolean;
export type ReactFragment = ReactEmpty | Iterable<React$Node>;
export type ReactNodeList = ReactEmpty | React$Node;
export type ReactText = string | number;
export type ReactProvider<T> = {
$$typeof: symbol | number,
type: ReactContext<T>,
key: null | string,
ref: null,
props: {
value: T,
children?: ReactNodeList,
},
};
export type ReactConsumerType<T> = {
$$typeof: symbol | number,
_context: ReactContext<T>,
};
export type ReactConsumer<T> = {
$$typeof: symbol | number,
type: ReactConsumerType<T>,
key: null | string,
ref: null,
props: {
children: (value: T) => ReactNodeList,
},
};
export type ReactContext<T> = {
$$typeof: symbol | number,
Consumer: ReactConsumerType<T>,
Provider: ReactContext<T>,
_currentValue: T,
_currentValue2: T,
_threadCount: number,
// DEV only
_currentRenderer?: Object | null,
_currentRenderer2?: Object | null,
// This value may be added by application code
// to improve DEV tooling display names
displayName?: string,
};
export type ReactPortal = {
$$typeof: symbol | number,
key: null | string,
containerInfo: any,
children: ReactNodeList,
// TODO: figure out the API for cross-renderer implementation.
implementation: any,
};
export type RefObject = {
current: any,
};
export type ReactScope = {
$$typeof: symbol | number,
};
export type ReactScopeQuery = (
type: string,
props: {[string]: mixed},
instance: mixed,
) => boolean;
export type ReactScopeInstance = {
DO_NOT_USE_queryAllNodes(ReactScopeQuery): null | Array<Object>,
DO_NOT_USE_queryFirstNode(ReactScopeQuery): null | Object,
containsNode(Object): boolean,
getChildContextValues: <T>(context: ReactContext<T>) => Array<T>,
};
// The subset of a Thenable required by things thrown by Suspense.
// This doesn't require a value to be passed to either handler.
export interface Wakeable {
then(onFulfill: () => mixed, onReject: () => mixed): void | Wakeable;
}
// The subset of a Promise that React APIs rely on. This resolves a value.
// This doesn't require a return value neither from the handler nor the
// then function.
interface ThenableImpl<T> {
then(
onFulfill: (value: T) => mixed,
onReject: (error: mixed) => mixed,
): void | Wakeable;
}
interface UntrackedThenable<T> extends ThenableImpl<T> {
status?: void;
_debugInfo?: null | ReactDebugInfo;
}
export interface PendingThenable<T> extends ThenableImpl<T> {
status: 'pending';
_debugInfo?: null | ReactDebugInfo;
}
export interface FulfilledThenable<T> extends ThenableImpl<T> {
status: 'fulfilled';
value: T;
_debugInfo?: null | ReactDebugInfo;
}
export interface RejectedThenable<T> extends ThenableImpl<T> {
status: 'rejected';
reason: mixed;
_debugInfo?: null | ReactDebugInfo;
}
export type Thenable<T> =
| UntrackedThenable<T>
| PendingThenable<T>
| FulfilledThenable<T>
| RejectedThenable<T>;
export type OffscreenMode =
| 'hidden'
| 'unstable-defer-without-hiding'
| 'visible'
| 'manual';
export type StartTransitionOptions = {
name?: string,
};
export type Usable<T> = Thenable<T> | ReactContext<T>;
export type ReactCustomFormAction = {
name?: string,
action?: string,
encType?: string,
method?: string,
target?: string,
data?: null | FormData,
};
// This is an opaque type returned by decodeFormState on the server, but it's
// defined in this shared file because the same type is used by React on
// the client.
export type ReactFormState<S, ReferenceId> = [
S /* actual state value */,
string /* key path */,
ReferenceId /* Server Reference ID */,
number /* number of bound arguments */,
];
export type Awaited<T> = T extends null | void
? T // special case for `null | undefined` when not in `--strictNullChecks` mode
: T extends Object // `await` only unwraps object types with a callable then. Non-object types are not unwrapped.
? T extends {then(onfulfilled: infer F): any} // thenable, extracts the first argument to `then()`
? F extends (value: infer V) => any // if the argument to `then` is callable, extracts the argument
? Awaited<V> // recursively unwrap the value
: empty // the argument to `then` was not callable.
: T // argument was not an object
: T; // non-thenable
export type ReactCallSite = [
string, // function name
string, // file name TODO: model nested eval locations as nested arrays
number, // line number
number, // column number
];
export type ReactStackTrace = Array<ReactCallSite>;
export type ReactComponentInfo = {
+name?: string,
+env?: string,
+key?: null | string,
+owner?: null | ReactComponentInfo,
+stack?: null | ReactStackTrace,
// Stashed Data for the Specific Execution Environment. Not part of the transport protocol
+debugStack?: null | Error,
+debugTask?: null | ConsoleTask,
};
export type ReactAsyncInfo = {
+started?: number,
+completed?: number,
+stack?: null | ReactStackTrace,
};
export type ReactDebugInfo = Array<ReactComponentInfo | ReactAsyncInfo>;