mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Recoil uses useMutableSource behind a flag. I thought this was fine because Recoil isn't used in any concurrent roots, so the behavior would be the same, but it turns out that it is used by concurrent roots in a few places. I'm not expecting it to be hard to migrate to useSyncExternalStore, but to de-risk the change I'm going to roll it out gradually with a flag. In the meantime, I've added back the useMutableSource API.
72 lines
2.1 KiB
JavaScript
72 lines
2.1 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its 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 ReactSharedInternals from 'shared/ReactSharedInternals';
|
|
import invariant from 'shared/invariant';
|
|
|
|
const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
|
|
|
|
function unsupported() {
|
|
invariant(false, 'This feature is not supported by ReactSuspenseTestUtils.');
|
|
}
|
|
|
|
export function waitForSuspense<T>(fn: () => T): Promise<T> {
|
|
const cache: Map<Function, mixed> = new Map();
|
|
const testDispatcher: Dispatcher = {
|
|
getCacheForType<R>(resourceType: () => R): R {
|
|
let entry: R | void = (cache.get(resourceType): any);
|
|
if (entry === undefined) {
|
|
entry = resourceType();
|
|
// TODO: Warn if undefined?
|
|
cache.set(resourceType, entry);
|
|
}
|
|
return entry;
|
|
},
|
|
readContext: unsupported,
|
|
useContext: unsupported,
|
|
useMemo: unsupported,
|
|
useReducer: unsupported,
|
|
useRef: unsupported,
|
|
useState: unsupported,
|
|
useInsertionEffect: unsupported,
|
|
useLayoutEffect: unsupported,
|
|
useCallback: unsupported,
|
|
useImperativeHandle: unsupported,
|
|
useEffect: unsupported,
|
|
useDebugValue: unsupported,
|
|
useDeferredValue: unsupported,
|
|
useTransition: unsupported,
|
|
useOpaqueIdentifier: unsupported,
|
|
useMutableSource: unsupported,
|
|
useSyncExternalStore: unsupported,
|
|
useCacheRefresh: unsupported,
|
|
};
|
|
// Not using async/await because we don't compile it.
|
|
return new Promise((resolve, reject) => {
|
|
function retry() {
|
|
const prevDispatcher = ReactCurrentDispatcher.current;
|
|
ReactCurrentDispatcher.current = testDispatcher;
|
|
try {
|
|
const result = fn();
|
|
resolve(result);
|
|
} catch (thrownValue) {
|
|
if (typeof thrownValue.then === 'function') {
|
|
thrownValue.then(retry, retry);
|
|
} else {
|
|
reject(thrownValue);
|
|
}
|
|
} finally {
|
|
ReactCurrentDispatcher.current = prevDispatcher;
|
|
}
|
|
}
|
|
retry();
|
|
});
|
|
}
|