mirror of
https://github.com/facebook/react.git
synced 2026-02-25 13:13:03 +00:00
## Summary This PR cleans up `useMutableSource`. This has been blocked by a remaining dependency internally at Meta, but that has now been deleted. <!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? --> ## How did you test this change? ``` yarn flow yarn lint yarn test --prod ``` <!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes the user interface. How exactly did you verify that your PR solves the issue you wanted to solve? If you leave this empty, your PR will very likely be closed. -->
156 lines
4.6 KiB
JavaScript
156 lines
4.6 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
|
|
*/
|
|
|
|
import type {Dispatcher} from 'react-reconciler/src/ReactInternalTypes';
|
|
import type {Request} from './ReactFlightServer';
|
|
import type {ReactServerContext, Thenable, Usable} from 'shared/ReactTypes';
|
|
import type {ThenableState} from './ReactFlightThenable';
|
|
import {
|
|
REACT_SERVER_CONTEXT_TYPE,
|
|
REACT_MEMO_CACHE_SENTINEL,
|
|
} from 'shared/ReactSymbols';
|
|
import {readContext as readContextImpl} from './ReactFlightNewContext';
|
|
import {createThenableState, trackUsedThenable} from './ReactFlightThenable';
|
|
import {isClientReference} from './ReactFlightServerConfig';
|
|
|
|
let currentRequest = null;
|
|
let thenableIndexCounter = 0;
|
|
let thenableState = null;
|
|
|
|
export function prepareToUseHooksForRequest(request: Request) {
|
|
currentRequest = request;
|
|
}
|
|
|
|
export function resetHooksForRequest() {
|
|
currentRequest = null;
|
|
}
|
|
|
|
export function prepareToUseHooksForComponent(
|
|
prevThenableState: ThenableState | null,
|
|
) {
|
|
thenableIndexCounter = 0;
|
|
thenableState = prevThenableState;
|
|
}
|
|
|
|
export function getThenableStateAfterSuspending(): null | ThenableState {
|
|
const state = thenableState;
|
|
thenableState = null;
|
|
return state;
|
|
}
|
|
|
|
function readContext<T>(context: ReactServerContext<T>): T {
|
|
if (__DEV__) {
|
|
if (context.$$typeof !== REACT_SERVER_CONTEXT_TYPE) {
|
|
if (isClientReference(context)) {
|
|
console.error('Cannot read a Client Context from a Server Component.');
|
|
} else {
|
|
console.error(
|
|
'Only createServerContext is supported in Server Components.',
|
|
);
|
|
}
|
|
}
|
|
if (currentRequest === null) {
|
|
console.error(
|
|
'Context can only be read while React is rendering. ' +
|
|
'In classes, you can read it in the render method or getDerivedStateFromProps. ' +
|
|
'In function components, you can read it directly in the function body, but not ' +
|
|
'inside Hooks like useReducer() or useMemo().',
|
|
);
|
|
}
|
|
}
|
|
return readContextImpl(context);
|
|
}
|
|
|
|
export const HooksDispatcher: Dispatcher = {
|
|
useMemo<T>(nextCreate: () => T): T {
|
|
return nextCreate();
|
|
},
|
|
useCallback<T>(callback: T): T {
|
|
return callback;
|
|
},
|
|
useDebugValue(): void {},
|
|
useDeferredValue: (unsupportedHook: any),
|
|
useTransition: (unsupportedHook: any),
|
|
readContext,
|
|
useContext: readContext,
|
|
useReducer: (unsupportedHook: any),
|
|
useRef: (unsupportedHook: any),
|
|
useState: (unsupportedHook: any),
|
|
useInsertionEffect: (unsupportedHook: any),
|
|
useLayoutEffect: (unsupportedHook: any),
|
|
useImperativeHandle: (unsupportedHook: any),
|
|
useEffect: (unsupportedHook: any),
|
|
useId,
|
|
useSyncExternalStore: (unsupportedHook: any),
|
|
useCacheRefresh(): <T>(?() => T, ?T) => void {
|
|
return unsupportedRefresh;
|
|
},
|
|
useMemoCache(size: number): Array<any> {
|
|
const data = new Array<any>(size);
|
|
for (let i = 0; i < size; i++) {
|
|
data[i] = REACT_MEMO_CACHE_SENTINEL;
|
|
}
|
|
return data;
|
|
},
|
|
use,
|
|
};
|
|
|
|
function unsupportedHook(): void {
|
|
throw new Error('This Hook is not supported in Server Components.');
|
|
}
|
|
|
|
function unsupportedRefresh(): void {
|
|
throw new Error(
|
|
'Refreshing the cache is not supported in Server Components.',
|
|
);
|
|
}
|
|
|
|
function useId(): string {
|
|
if (currentRequest === null) {
|
|
throw new Error('useId can only be used while React is rendering');
|
|
}
|
|
const id = currentRequest.identifierCount++;
|
|
// use 'S' for Flight components to distinguish from 'R' and 'r' in Fizz/Client
|
|
return ':' + currentRequest.identifierPrefix + 'S' + id.toString(32) + ':';
|
|
}
|
|
|
|
function use<T>(usable: Usable<T>): T {
|
|
if (
|
|
(usable !== null && typeof usable === 'object') ||
|
|
typeof usable === 'function'
|
|
) {
|
|
// $FlowFixMe[method-unbinding]
|
|
if (typeof usable.then === 'function') {
|
|
// This is a thenable.
|
|
const thenable: Thenable<T> = (usable: any);
|
|
|
|
// Track the position of the thenable within this fiber.
|
|
const index = thenableIndexCounter;
|
|
thenableIndexCounter += 1;
|
|
|
|
if (thenableState === null) {
|
|
thenableState = createThenableState();
|
|
}
|
|
return trackUsedThenable(thenableState, thenable, index);
|
|
} else if (usable.$$typeof === REACT_SERVER_CONTEXT_TYPE) {
|
|
const context: ReactServerContext<T> = (usable: any);
|
|
return readContext(context);
|
|
}
|
|
}
|
|
|
|
if (__DEV__) {
|
|
if (isClientReference(usable)) {
|
|
console.error('Cannot use() an already resolved Client Reference.');
|
|
}
|
|
}
|
|
|
|
// eslint-disable-next-line react-internal/safe-string-coercion
|
|
throw new Error('An unsupported type was passed to use(): ' + String(usable));
|
|
}
|