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 {Dispatcher} from 'react-reconciler/src/ReactInternalTypes';
    
  11. import type {Request} from './ReactFlightServer';
    
  12. import type {ReactServerContext, Thenable, Usable} from 'shared/ReactTypes';
    
  13. import type {ThenableState} from './ReactFlightThenable';
    
  14. import {
    
  15.   REACT_SERVER_CONTEXT_TYPE,
    
  16.   REACT_MEMO_CACHE_SENTINEL,
    
  17. } from 'shared/ReactSymbols';
    
  18. import {readContext as readContextImpl} from './ReactFlightNewContext';
    
  19. import {createThenableState, trackUsedThenable} from './ReactFlightThenable';
    
  20. import {isClientReference} from './ReactFlightServerConfig';
    
  21. 
    
  22. let currentRequest = null;
    
  23. let thenableIndexCounter = 0;
    
  24. let thenableState = null;
    
  25. 
    
  26. export function prepareToUseHooksForRequest(request: Request) {
    
  27.   currentRequest = request;
    
  28. }
    
  29. 
    
  30. export function resetHooksForRequest() {
    
  31.   currentRequest = null;
    
  32. }
    
  33. 
    
  34. export function prepareToUseHooksForComponent(
    
  35.   prevThenableState: ThenableState | null,
    
  36. ) {
    
  37.   thenableIndexCounter = 0;
    
  38.   thenableState = prevThenableState;
    
  39. }
    
  40. 
    
  41. export function getThenableStateAfterSuspending(): null | ThenableState {
    
  42.   const state = thenableState;
    
  43.   thenableState = null;
    
  44.   return state;
    
  45. }
    
  46. 
    
  47. function readContext<T>(context: ReactServerContext<T>): T {
    
  48.   if (__DEV__) {
    
  49.     if (context.$$typeof !== REACT_SERVER_CONTEXT_TYPE) {
    
  50.       if (isClientReference(context)) {
    
  51.         console.error('Cannot read a Client Context from a Server Component.');
    
  52.       } else {
    
  53.         console.error(
    
  54.           'Only createServerContext is supported in Server Components.',
    
  55.         );
    
  56.       }
    
  57.     }
    
  58.     if (currentRequest === null) {
    
  59.       console.error(
    
  60.         'Context can only be read while React is rendering. ' +
    
  61.           'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
    
  62.           'In function components, you can read it directly in the function body, but not ' +
    
  63.           'inside Hooks like useReducer() or useMemo().',
    
  64.       );
    
  65.     }
    
  66.   }
    
  67.   return readContextImpl(context);
    
  68. }
    
  69. 
    
  70. export const HooksDispatcher: Dispatcher = {
    
  71.   useMemo<T>(nextCreate: () => T): T {
    
  72.     return nextCreate();
    
  73.   },
    
  74.   useCallback<T>(callback: T): T {
    
  75.     return callback;
    
  76.   },
    
  77.   useDebugValue(): void {},
    
  78.   useDeferredValue: (unsupportedHook: any),
    
  79.   useTransition: (unsupportedHook: any),
    
  80.   readContext,
    
  81.   useContext: readContext,
    
  82.   useReducer: (unsupportedHook: any),
    
  83.   useRef: (unsupportedHook: any),
    
  84.   useState: (unsupportedHook: any),
    
  85.   useInsertionEffect: (unsupportedHook: any),
    
  86.   useLayoutEffect: (unsupportedHook: any),
    
  87.   useImperativeHandle: (unsupportedHook: any),
    
  88.   useEffect: (unsupportedHook: any),
    
  89.   useId,
    
  90.   useSyncExternalStore: (unsupportedHook: any),
    
  91.   useCacheRefresh(): <T>(?() => T, ?T) => void {
    
  92.     return unsupportedRefresh;
    
  93.   },
    
  94.   useMemoCache(size: number): Array<any> {
    
  95.     const data = new Array<any>(size);
    
  96.     for (let i = 0; i < size; i++) {
    
  97.       data[i] = REACT_MEMO_CACHE_SENTINEL;
    
  98.     }
    
  99.     return data;
    
  100.   },
    
  101.   use,
    
  102. };
    
  103. 
    
  104. function unsupportedHook(): void {
    
  105.   throw new Error('This Hook is not supported in Server Components.');
    
  106. }
    
  107. 
    
  108. function unsupportedRefresh(): void {
    
  109.   throw new Error(
    
  110.     'Refreshing the cache is not supported in Server Components.',
    
  111.   );
    
  112. }
    
  113. 
    
  114. function useId(): string {
    
  115.   if (currentRequest === null) {
    
  116.     throw new Error('useId can only be used while React is rendering');
    
  117.   }
    
  118.   const id = currentRequest.identifierCount++;
    
  119.   // use 'S' for Flight components to distinguish from 'R' and 'r' in Fizz/Client
    
  120.   return ':' + currentRequest.identifierPrefix + 'S' + id.toString(32) + ':';
    
  121. }
    
  122. 
    
  123. function use<T>(usable: Usable<T>): T {
    
  124.   if (
    
  125.     (usable !== null && typeof usable === 'object') ||
    
  126.     typeof usable === 'function'
    
  127.   ) {
    
  128.     // $FlowFixMe[method-unbinding]
    
  129.     if (typeof usable.then === 'function') {
    
  130.       // This is a thenable.
    
  131.       const thenable: Thenable<T> = (usable: any);
    
  132. 
    
  133.       // Track the position of the thenable within this fiber.
    
  134.       const index = thenableIndexCounter;
    
  135.       thenableIndexCounter += 1;
    
  136. 
    
  137.       if (thenableState === null) {
    
  138.         thenableState = createThenableState();
    
  139.       }
    
  140.       return trackUsedThenable(thenableState, thenable, index);
    
  141.     } else if (usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
    
  142.       const context: ReactServerContext<T> = (usable: any);
    
  143.       return readContext(context);
    
  144.     }
    
  145.   }
    
  146. 
    
  147.   if (__DEV__) {
    
  148.     if (isClientReference(usable)) {
    
  149.       console.error('Cannot use() an already resolved Client Reference.');
    
  150.     }
    
  151.   }
    
  152. 
    
  153.   // eslint-disable-next-line react-internal/safe-string-coercion
    
  154.   throw new Error('An unsupported type was passed to use(): ' + String(usable));
    
  155. }