main
js 464 lines 14.7 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import type {
11 RefObject,
12 ReactContext,
13 StartTransitionOptions,
14 Wakeable,
15 Usable,
16 ReactFormState,
17 Awaited,
18 ReactComponentInfo,
19 ReactDebugInfo,
20 ReactKey,
21 } from 'shared/ReactTypes';
22 import type {TransitionTypes} from 'react/src/ReactTransitionType';
23 import type {WorkTag} from './ReactWorkTags';
24 import type {TypeOfMode} from './ReactTypeOfMode';
25 import type {Flags} from './ReactFiberFlags';
26 import type {Lane, Lanes, LaneMap} from './ReactFiberLane';
27 import type {RootTag} from './ReactRootTags';
28 import type {
29 Container,
30 Instance,
31 TimeoutHandle,
32 NoTimeout,
33 ActivityInstance,
34 SuspenseInstance,
35 TransitionStatus,
36 } from './ReactFiberConfig';
37 import type {Cache} from './ReactFiberCacheComponent';
38 import type {Transition} from 'react/src/ReactStartTransition';
39 import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent';
40 import type {ConcurrentUpdate} from './ReactFiberConcurrentUpdates';
41 import type {ComponentStackNode} from 'react-server/src/ReactFizzComponentStack';
42 import type {ThenableState} from './ReactFiberThenable';
43 import type {ScheduledGesture} from './ReactFiberGestureScheduler';
44
45 // Unwind Circular: moved from ReactFiberHooks.old
46 export type HookType =
47 | 'useState'
48 | 'useReducer'
49 | 'useContext'
50 | 'useRef'
51 | 'useEffect'
52 | 'useEffectEvent'
53 | 'useInsertionEffect'
54 | 'useLayoutEffect'
55 | 'useCallback'
56 | 'useMemo'
57 | 'useImperativeHandle'
58 | 'useDebugValue'
59 | 'useDeferredValue'
60 | 'useTransition'
61 | 'useSyncExternalStore'
62 | 'useId'
63 | 'useCacheRefresh'
64 | 'useOptimistic'
65 | 'useFormState'
66 | 'useActionState';
67
68 export type ContextDependency<T> = {
69 context: ReactContext<T>,
70 next: ContextDependency<mixed> | null,
71 memoizedValue: T,
72 ...
73 };
74
75 export type Dependencies = {
76 lanes: Lanes,
77 firstContext: ContextDependency<mixed> | null,
78 _debugThenableState?: null | ThenableState, // DEV-only
79 ...
80 };
81
82 export type MemoCache = {
83 data: Array<Array<any>>,
84 index: number,
85 };
86
87 // A Fiber is work on a Component that needs to be done or was done. There can
88 // be more than one per component.
89 export type Fiber = {
90 // These first fields are conceptually members of an Instance. This used to
91 // be split into a separate type and intersected with the other Fiber fields,
92 // but until Flow fixes its intersection bugs, we've merged them into a
93 // single type.
94
95 // An Instance is shared between all versions of a component. We can easily
96 // break this out into a separate object to avoid copying so much to the
97 // alternate versions of the tree. We put this on a single object for now to
98 // minimize the number of objects created during the initial render.
99
100 // Tag identifying the type of fiber.
101 tag: WorkTag,
102
103 // Unique identifier of this child.
104 key: ReactKey,
105
106 // The value of element.type which is used to preserve the identity during
107 // reconciliation of this child.
108 elementType: any,
109
110 // The resolved function/class/ associated with this fiber.
111 type: any,
112
113 // The local state associated with this fiber.
114 stateNode: any,
115
116 // Conceptual aliases
117 // parent : Instance -> return The parent happens to be the same as the
118 // return fiber since we've merged the fiber and instance.
119
120 // Remaining fields belong to Fiber
121
122 // The Fiber to return to after finishing processing this one.
123 // This is effectively the parent, but there can be multiple parents (two)
124 // so this is only the parent of the thing we're currently processing.
125 // It is conceptually the same as the return address of a stack frame.
126 return: Fiber | null,
127
128 // Singly Linked List Tree Structure.
129 child: Fiber | null,
130 sibling: Fiber | null,
131 index: number,
132
133 // The ref last used to attach this node.
134 // I'll avoid adding an owner field for prod and model that as functions.
135 ref:
136 | null
137 | (((handle: mixed) => void) & {_stringRef: ?string, ...})
138 | RefObject,
139
140 refCleanup: null | (() => void),
141
142 // Input is the data coming into process this fiber. Arguments. Props.
143 pendingProps: any, // This type will be more specific once we overload the tag.
144 memoizedProps: any, // The props used to create the output.
145
146 // A queue of state updates and callbacks.
147 updateQueue: mixed,
148
149 // The state used to create the output
150 memoizedState: any,
151
152 // Dependencies (contexts, events) for this fiber, if it has any
153 dependencies: Dependencies | null,
154
155 // Bitfield that describes properties about the fiber and its subtree. E.g.
156 // the ConcurrentMode flag indicates whether the subtree should be async-by-
157 // default. When a fiber is created, it inherits the mode of its
158 // parent. Additional flags can be set at creation time, but after that the
159 // value should remain unchanged throughout the fiber's lifetime, particularly
160 // before its child fibers are created.
161 mode: TypeOfMode,
162
163 // Effect
164 flags: Flags,
165 subtreeFlags: Flags,
166 deletions: Array<Fiber> | null,
167
168 lanes: Lanes,
169 childLanes: Lanes,
170
171 // This is a pooled version of a Fiber. Every fiber that gets updated will
172 // eventually have a pair. There are cases when we can clean up pairs to save
173 // memory if we need to.
174 alternate: Fiber | null,
175
176 // Time spent rendering this Fiber and its descendants for the current update.
177 // This tells us how well the tree makes use of sCU for memoization.
178 // It is reset to 0 each time we render and only updated when we don't bailout.
179 // This field is only set when the enableProfilerTimer flag is enabled.
180 actualDuration?: number,
181
182 // If the Fiber is currently active in the "render" phase,
183 // This marks the time at which the work began.
184 // This field is only set when the enableProfilerTimer flag is enabled.
185 actualStartTime?: number,
186
187 // Duration of the most recent render time for this Fiber.
188 // This value is not updated when we bailout for memoization purposes.
189 // This field is only set when the enableProfilerTimer flag is enabled.
190 selfBaseDuration?: number,
191
192 // Sum of base times for all descendants of this Fiber.
193 // This value bubbles up during the "complete" phase.
194 // This field is only set when the enableProfilerTimer flag is enabled.
195 treeBaseDuration?: number,
196
197 // Conceptual aliases
198 // workInProgress : Fiber -> alternate The alternate used for reuse happens
199 // to be the same as work in progress.
200 // __DEV__ only
201
202 _debugInfo?: ReactDebugInfo | null,
203 _debugOwner?: ReactComponentInfo | Fiber | null,
204 _debugStack?: Error | null,
205 _debugTask?: ConsoleTask | null,
206 _debugNeedsRemount?: boolean,
207
208 // Used to verify that the order of hooks does not change between renders.
209 _debugHookTypes?: Array<HookType> | null,
210 };
211
212 type BaseFiberRootProperties = {
213 // The type of root (legacy, batched, concurrent, etc.)
214 tag: RootTag,
215
216 // Any additional information from the host associated with this root.
217 containerInfo: Container,
218 // Used only by persistent updates.
219 pendingChildren: any,
220 // The currently active root fiber. This is the mutable root of the tree.
221 current: Fiber,
222
223 pingCache: WeakMap<Wakeable, Set<mixed>> | Map<Wakeable, Set<mixed>> | null,
224
225 // Timeout handle returned by setTimeout. Used to cancel a pending timeout, if
226 // it's superseded by a new one.
227 timeoutHandle: TimeoutHandle | NoTimeout,
228 // When a root has a pending commit scheduled, calling this function will
229 // cancel it.
230 // TODO: Can this be consolidated with timeoutHandle?
231 cancelPendingCommit: null | (() => void),
232 // Top context object, used by renderSubtreeIntoContainer
233 context: Object | null,
234 pendingContext: Object | null,
235
236 // Used to create a linked list that represent all the roots that have
237 // pending work scheduled on them.
238 next: FiberRoot | null,
239
240 // Node returned by Scheduler.scheduleCallback. Represents the next rendering
241 // task that the root will work on.
242 callbackNode: any,
243 callbackPriority: Lane,
244 expirationTimes: LaneMap<number>,
245 hiddenUpdates: LaneMap<Array<ConcurrentUpdate> | null>,
246
247 pendingLanes: Lanes,
248 suspendedLanes: Lanes,
249 pingedLanes: Lanes,
250 warmLanes: Lanes,
251 expiredLanes: Lanes,
252 indicatorLanes: Lanes, // enableDefaultTransitionIndicator only
253 errorRecoveryDisabledLanes: Lanes,
254 shellSuspendCounter: number,
255
256 entangledLanes: Lanes,
257 entanglements: LaneMap<Lanes>,
258
259 pooledCache: Cache | null,
260 pooledCacheLanes: Lanes,
261
262 // TODO: In Fizz, id generation is specific to each server config. Maybe we
263 // should do this in Fiber, too? Deferring this decision for now because
264 // there's no other place to store the prefix except for an internal field on
265 // the public createRoot object, which the fiber tree does not currently have
266 // a reference to.
267 identifierPrefix: string,
268
269 onUncaughtError: (
270 error: mixed,
271 errorInfo: {+componentStack?: ?string},
272 ) => void,
273 onCaughtError: (
274 error: mixed,
275 errorInfo: {
276 +componentStack?: ?string,
277 +errorBoundary?: ?component(...props: any),
278 },
279 ) => void,
280 onRecoverableError: (
281 error: mixed,
282 errorInfo: {+componentStack?: ?string},
283 ) => void,
284
285 // enableDefaultTransitionIndicator only
286 onDefaultTransitionIndicator: () => void | (() => void),
287 pendingIndicator: null | (() => void),
288
289 formState: ReactFormState<any, any> | null,
290
291 // enableViewTransition only
292 transitionTypes: null | TransitionTypes, // TODO: Make this a LaneMap.
293 // enableGestureTransition only
294 pendingGestures: null | ScheduledGesture,
295 gestureClone: null | Instance,
296 };
297
298 // The following attributes are only used by DevTools and are only present in DEV builds.
299 // They enable DevTools Profiler UI to show which Fiber(s) scheduled a given commit.
300 type UpdaterTrackingOnlyFiberRootProperties = {
301 memoizedUpdaters: Set<Fiber>,
302 pendingUpdatersLaneMap: LaneMap<Set<Fiber>>,
303 };
304
305 export type SuspenseHydrationCallbacks = {
306 +onHydrated?: (
307 hydrationBoundary: SuspenseInstance | ActivityInstance,
308 ) => void,
309 +onDeleted?: (hydrationBoundary: SuspenseInstance | ActivityInstance) => void,
310 ...
311 };
312
313 // The follow fields are only used by enableSuspenseCallback for hydration.
314 type SuspenseCallbackOnlyFiberRootProperties = {
315 hydrationCallbacks: null | SuspenseHydrationCallbacks,
316 };
317
318 export type TransitionTracingCallbacks = {
319 onTransitionStart?: (transitionName: string, startTime: number) => void,
320 onTransitionProgress?: (
321 transitionName: string,
322 startTime: number,
323 currentTime: number,
324 pending: Array<{name: null | string}>,
325 ) => void,
326 onTransitionIncomplete?: (
327 transitionName: string,
328 startTime: number,
329 deletions: Array<{
330 type: string,
331 name?: string | null,
332 endTime: number,
333 }>,
334 ) => void,
335 onTransitionComplete?: (
336 transitionName: string,
337 startTime: number,
338 endTime: number,
339 ) => void,
340 onMarkerProgress?: (
341 transitionName: string,
342 marker: string,
343 startTime: number,
344 currentTime: number,
345 pending: Array<{name: null | string}>,
346 ) => void,
347 onMarkerIncomplete?: (
348 transitionName: string,
349 marker: string,
350 startTime: number,
351 deletions: Array<{
352 type: string,
353 name?: string | null,
354 endTime: number,
355 }>,
356 ) => void,
357 onMarkerComplete?: (
358 transitionName: string,
359 marker: string,
360 startTime: number,
361 endTime: number,
362 ) => void,
363 };
364
365 // The following fields are only used in transition tracing in Profile builds
366 type TransitionTracingOnlyFiberRootProperties = {
367 transitionCallbacks: null | TransitionTracingCallbacks,
368 transitionLanes: LaneMap<Set<Transition> | null>,
369 // Transitions on the root can be represented as a bunch of tracing markers.
370 // Each entangled group of transitions can be treated as a tracing marker.
371 // It will have a set of pending suspense boundaries. These transitions
372 // are considered complete when the pending suspense boundaries set is
373 // empty. We can represent this as a Map of transitions to suspense
374 // boundary sets
375 incompleteTransitions: Map<Transition, TracingMarkerInstance>,
376 };
377
378 type ProfilerCommitHooksOnlyFiberRootProperties = {
379 effectDuration: number,
380 passiveEffectDuration: number,
381 };
382
383 // Exported FiberRoot type includes all properties,
384 // To avoid requiring potentially error-prone :any casts throughout the project.
385 // The types are defined separately within this file to ensure they stay in sync.
386 export type FiberRoot = {
387 ...BaseFiberRootProperties,
388 ...SuspenseCallbackOnlyFiberRootProperties,
389 ...UpdaterTrackingOnlyFiberRootProperties,
390 ...TransitionTracingOnlyFiberRootProperties,
391 ...ProfilerCommitHooksOnlyFiberRootProperties,
392 };
393
394 type BasicStateAction<S> = (S => S) | S;
395 type Dispatch<A> = A => void;
396
397 export type Dispatcher = {
398 use: <T>(Usable<T>) => T,
399 readContext<T>(context: ReactContext<T>): T,
400 useState<S>(initialState: (() => S) | S): [S, Dispatch<BasicStateAction<S>>],
401 useReducer<S, I, A>(
402 reducer: (S, A) => S,
403 initialArg: I,
404 init?: (I) => S,
405 ): [S, Dispatch<A>],
406 useContext<T>(context: ReactContext<T>): T,
407 useRef<T>(initialValue: T): {current: T},
408 useEffect(
409 create: () => (() => void) | void,
410 deps: Array<mixed> | void | null,
411 ): void,
412 useEffectEvent: <Args, F: (...Array<Args>) => mixed>(callback: F) => F,
413 useInsertionEffect(
414 create: () => (() => void) | void,
415 deps: Array<mixed> | void | null,
416 ): void,
417 useLayoutEffect(
418 create: () => (() => void) | void,
419 deps: Array<mixed> | void | null,
420 ): void,
421 useCallback<T>(callback: T, deps: Array<mixed> | void | null): T,
422 useMemo<T>(nextCreate: () => T, deps: Array<mixed> | void | null): T,
423 useImperativeHandle<T>(
424 ref: {current: T | null} | ((inst: T | null) => mixed) | null | void,
425 create: () => T,
426 deps: Array<mixed> | void | null,
427 ): void,
428 useDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void,
429 useDeferredValue<T>(value: T, initialValue?: T): T,
430 useTransition(): [
431 boolean,
432 (callback: () => void, options?: StartTransitionOptions) => void,
433 ],
434 useSyncExternalStore<T>(
435 subscribe: (() => void) => () => void,
436 getSnapshot: () => T,
437 getServerSnapshot?: () => T,
438 ): T,
439 useId(): string,
440 useCacheRefresh: () => <T>(?() => T, ?T) => void,
441 useMemoCache: (size: number) => Array<any>,
442 useHostTransitionStatus: () => TransitionStatus,
443 useOptimistic: <S, A>(
444 passthrough: S,
445 reducer: ?(S, A) => S,
446 ) => [S, (A) => void],
447 useFormState: <S, P>(
448 action: (Awaited<S>, P) => S,
449 initialState: Awaited<S>,
450 permalink?: string,
451 ) => [Awaited<S>, (P) => void, boolean],
452 useActionState: <S, P>(
453 action: (Awaited<S>, P) => S,
454 initialState: Awaited<S>,
455 permalink?: string,
456 ) => [Awaited<S>, (P) => void, boolean],
457 };
458
459 export type AsyncDispatcher = {
460 getCacheForType: <T>(resourceType: () => T) => T,
461 cacheSignal: () => null | AbortSignal,
462 // DEV-only
463 getOwner: () => null | Fiber | ReactComponentInfo | ComponentStackNode,
464 };