Remove useMutableSource (#27011)

## 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.
-->
This commit is contained in:
Noah Lemen
2023-06-27 12:45:46 -04:00
committed by GitHub
parent 6aacd3fa15
commit 80d9a40114
30 changed files with 4 additions and 3023 deletions

View File

@@ -8,9 +8,6 @@
*/
import type {
MutableSource,
MutableSourceGetSnapshotFn,
MutableSourceSubscribeFn,
ReactContext,
ReactProviderType,
StartTransitionOptions,
@@ -273,23 +270,6 @@ function useMemo<T>(
return value;
}
function useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
// useMutableSource() composes multiple hooks internally.
// Advance the current hook index the same number of times
// so that subsequent hooks have the right memoized state.
nextHook(); // MutableSource
nextHook(); // State
nextHook(); // Effect
nextHook(); // Effect
const value = getSnapshot(source._source);
hookLog.push({primitive: 'MutableSource', stackError: new Error(), value});
return value;
}
function useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
@@ -396,7 +376,6 @@ const Dispatcher: DispatcherType = {
useRef,
useState,
useTransition,
useMutableSource,
useSyncExternalStore,
useDeferredValue,
useId,

View File

@@ -1036,52 +1036,6 @@ describe('ReactHooksInspectionIntegration', () => {
]);
});
// @gate enableUseMutableSource
it('should support composite useMutableSource hook', () => {
const createMutableSource =
React.createMutableSource || React.unstable_createMutableSource;
const useMutableSource =
React.useMutableSource || React.unstable_useMutableSource;
const mutableSource = createMutableSource({}, () => 1);
function Foo(props) {
useMutableSource(
mutableSource,
() => 'snapshot',
() => {},
);
React.useMemo(() => 'memo', []);
React.useMemo(() => 'not used', []);
return <div />;
}
const renderer = ReactTestRenderer.create(<Foo />);
const childFiber = renderer.root.findByType(Foo)._currentFiber();
const tree = ReactDebugTools.inspectHooksOfFiber(childFiber);
expect(tree).toEqual([
{
id: 0,
isStateEditable: false,
name: 'MutableSource',
value: 'snapshot',
subHooks: [],
},
{
id: 1,
isStateEditable: false,
name: 'Memo',
value: 'memo',
subHooks: [],
},
{
id: 2,
isStateEditable: false,
name: 'Memo',
value: 'not used',
subHooks: [],
},
]);
});
it('should support composite useSyncExternalStore hook', () => {
const useSyncExternalStore = React.useSyncExternalStore;
function Foo() {

View File

@@ -7,7 +7,7 @@
* @flow
*/
import type {MutableSource, ReactNodeList} from 'shared/ReactTypes';
import type {ReactNodeList} from 'shared/ReactTypes';
import type {
FiberRoot,
TransitionTracingCallbacks,
@@ -47,7 +47,6 @@ export type CreateRootOptions = {
export type HydrateRootOptions = {
// Hydration options
hydratedSources?: Array<MutableSource<any>>,
onHydrated?: (suspenseNode: Comment) => void,
onDeleted?: (suspenseNode: Comment) => void,
// Options for all roots
@@ -77,7 +76,6 @@ import {
createHydrationContainer,
updateContainer,
findHostInstanceWithNoPortals,
registerMutableSourceForHydration,
flushSync,
isAlreadyRendering,
} from 'react-reconciler/src/ReactFiberReconciler';
@@ -298,8 +296,6 @@ export function hydrateRoot(
// For now we reuse the whole bag of options since they contain
// the hydration callbacks.
const hydrationCallbacks = options != null ? options : null;
// TODO: Delete this option
const mutableSources = (options != null && options.hydratedSources) || null;
let isStrictMode = false;
let concurrentUpdatesByDefaultOverride = false;
@@ -344,13 +340,6 @@ export function hydrateRoot(
// This can't be a comment node since hydration doesn't work on comment nodes anyway.
listenToAllSupportedEvents(container);
if (mutableSources) {
for (let i = 0; i < mutableSources.length; i++) {
const mutableSource = mutableSources[i];
registerMutableSourceForHydration(root, mutableSource);
}
}
// $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions
return new ReactDOMHydrationRoot(root);
}

View File

@@ -11,7 +11,6 @@ import type {
ReactProviderType,
ReactContext,
ReactNodeList,
MutableSource,
} from 'shared/ReactTypes';
import type {LazyComponent as LazyComponentType} from 'react/src/ReactLazy';
import type {Fiber, FiberRoot} from './ReactInternalTypes';
@@ -106,7 +105,6 @@ import {
enableTransitionTracing,
enableLegacyHidden,
enableCPUSuspense,
enableUseMutableSource,
enableFloat,
enableHostSingletons,
enableFormActions,
@@ -261,7 +259,6 @@ import {
getWorkInProgressRoot,
} from './ReactFiberWorkLoop';
import {enqueueConcurrentRenderForLane} from './ReactFiberConcurrentUpdates';
import {setWorkInProgressVersion} from './ReactMutableSource';
import {pushCacheProvider, CacheContext} from './ReactFiberCacheComponent';
import {
createCapturedValue,
@@ -1532,19 +1529,6 @@ function updateHostRoot(
} else {
// The outermost shell has not hydrated yet. Start hydrating.
enterHydrationState(workInProgress);
if (enableUseMutableSource) {
const mutableSourceEagerHydrationData =
root.mutableSourceEagerHydrationData;
if (mutableSourceEagerHydrationData != null) {
for (let i = 0; i < mutableSourceEagerHydrationData.length; i += 2) {
const mutableSource = ((mutableSourceEagerHydrationData[
i
]: any): MutableSource<any>);
const version = mutableSourceEagerHydrationData[i + 1];
setWorkInProgressVersion(mutableSource, version);
}
}
}
const child = mountChildFibers(
workInProgress,

View File

@@ -41,8 +41,6 @@ import {
diffInCommitPhase,
} from 'shared/ReactFeatureFlags';
import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource';
import {now} from './Scheduler';
import {
@@ -1038,7 +1036,6 @@ function completeWork(
popRootTransition(workInProgress, fiberRoot, renderLanes);
popHostContainer(workInProgress);
popTopLevelLegacyContextObject(workInProgress);
resetMutableSourceWorkInProgressVersions();
if (fiberRoot.pendingContext) {
fiberRoot.context = fiberRoot.pendingContext;
fiberRoot.pendingContext = null;

View File

@@ -8,9 +8,6 @@
*/
import type {
MutableSource,
MutableSourceGetSnapshotFn,
MutableSourceSubscribeFn,
ReactContext,
StartTransitionOptions,
Usable,
@@ -37,7 +34,6 @@ import {
enableCache,
enableUseRefAccessWarning,
enableLazyContextPropagation,
enableUseMutableSource,
enableTransitionTracing,
enableUseMemoCacheHook,
enableUseEffectEventHook,
@@ -74,7 +70,6 @@ import {
intersectLanes,
isTransitionLane,
markRootEntangled,
markRootMutableRead,
} from './ReactFiberLane';
import {
ContinuousEventPriority,
@@ -117,12 +112,6 @@ import {
checkIfWorkInProgressReceivedUpdate,
} from './ReactFiberBeginWork';
import {getIsHydrating} from './ReactFiberHydrationContext';
import {
getWorkInProgressVersion,
markSourceAsDirty,
setWorkInProgressVersion,
warnAboutMultipleRenderersDEV,
} from './ReactMutableSource';
import {logStateUpdateScheduled} from './DebugTracing';
import {
markStateUpdateScheduled,
@@ -1403,301 +1392,6 @@ function rerenderReducer<S, I, A>(
return [newState, dispatch];
}
type MutableSourceMemoizedState<Source, Snapshot> = {
refs: {
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
setSnapshot: Snapshot => void,
},
source: MutableSource<any>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
};
function readFromUnsubscribedMutableSource<Source, Snapshot>(
root: FiberRoot,
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
): Snapshot {
if (__DEV__) {
warnAboutMultipleRenderersDEV(source);
}
const getVersion = source._getVersion;
const version = getVersion(source._source);
// Is it safe for this component to read from this source during the current render?
let isSafeToReadFromSource = false;
// Check the version first.
// If this render has already been started with a specific version,
// we can use it alone to determine if we can safely read from the source.
const currentRenderVersion = getWorkInProgressVersion(source);
if (currentRenderVersion !== null) {
// It's safe to read if the store hasn't been mutated since the last time
// we read something.
isSafeToReadFromSource = currentRenderVersion === version;
} else {
// If there's no version, then this is the first time we've read from the
// source during the current render pass, so we need to do a bit more work.
// What we need to determine is if there are any hooks that already
// subscribed to the source, and if so, whether there are any pending
// mutations that haven't been synchronized yet.
//
// If there are no pending mutations, then `root.mutableReadLanes` will be
// empty, and we know we can safely read.
//
// If there *are* pending mutations, we may still be able to safely read
// if the currently rendering lanes are inclusive of the pending mutation
// lanes, since that guarantees that the value we're about to read from
// the source is consistent with the values that we read during the most
// recent mutation.
isSafeToReadFromSource = isSubsetOfLanes(
renderLanes,
root.mutableReadLanes,
);
if (isSafeToReadFromSource) {
// If it's safe to read from this source during the current render,
// store the version in case other components read from it.
// A changed version number will let those components know to throw and restart the render.
setWorkInProgressVersion(source, version);
}
}
if (isSafeToReadFromSource) {
const snapshot = getSnapshot(source._source);
if (__DEV__) {
if (typeof snapshot === 'function') {
console.error(
'Mutable source should not return a function as the snapshot value. ' +
'Functions may close over mutable values and cause tearing.',
);
}
}
return snapshot;
} else {
// This handles the special case of a mutable source being shared between renderers.
// In that case, if the source is mutated between the first and second renderer,
// The second renderer don't know that it needs to reset the WIP version during unwind,
// (because the hook only marks sources as dirty if it's written to their WIP version).
// That would cause this tear check to throw again and eventually be visible to the user.
// We can avoid this infinite loop by explicitly marking the source as dirty.
//
// This can lead to tearing in the first renderer when it resumes,
// but there's nothing we can do about that (short of throwing here and refusing to continue the render).
markSourceAsDirty(source);
// Intentioally throw an error to force React to retry synchronously. During
// the synchronous retry, it will block interleaved mutations, so we should
// get a consistent read. Therefore, the following error should never be
// visible to the user.
// We expect this error not to be thrown during the synchronous retry,
// because we blocked interleaved mutations.
throw new Error(
'Cannot read from mutable source during the current render without tearing. This may be a bug in React. Please file an issue.',
);
}
}
function useMutableSource<Source, Snapshot>(
hook: Hook,
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
if (!enableUseMutableSource) {
return (undefined: any);
}
const root = ((getWorkInProgressRoot(): any): FiberRoot);
if (root === null) {
throw new Error(
'Expected a work-in-progress root. This is a bug in React. Please file an issue.',
);
}
const getVersion = source._getVersion;
const version = getVersion(source._source);
const dispatcher = ReactCurrentDispatcher.current;
// eslint-disable-next-line prefer-const
let [currentSnapshot, setSnapshot] = dispatcher.useState(() =>
readFromUnsubscribedMutableSource(root, source, getSnapshot),
);
let snapshot = currentSnapshot;
// Grab a handle to the state hook as well.
// We use it to clear the pending update queue if we have a new source.
const stateHook = ((workInProgressHook: any): Hook);
const memoizedState = ((hook.memoizedState: any): MutableSourceMemoizedState<
Source,
Snapshot,
>);
const refs = memoizedState.refs;
const prevGetSnapshot = refs.getSnapshot;
const prevSource = memoizedState.source;
const prevSubscribe = memoizedState.subscribe;
const fiber = currentlyRenderingFiber;
hook.memoizedState = ({
refs,
source,
subscribe,
}: MutableSourceMemoizedState<Source, Snapshot>);
// Sync the values needed by our subscription handler after each commit.
dispatcher.useEffect(() => {
refs.getSnapshot = getSnapshot;
// Normally the dispatch function for a state hook never changes,
// but this hook recreates the queue in certain cases to avoid updates from stale sources.
// handleChange() below needs to reference the dispatch function without re-subscribing,
// so we use a ref to ensure that it always has the latest version.
refs.setSnapshot = setSnapshot;
// Check for a possible change between when we last rendered now.
const maybeNewVersion = getVersion(source._source);
if (!is(version, maybeNewVersion)) {
const maybeNewSnapshot = getSnapshot(source._source);
if (__DEV__) {
if (typeof maybeNewSnapshot === 'function') {
console.error(
'Mutable source should not return a function as the snapshot value. ' +
'Functions may close over mutable values and cause tearing.',
);
}
}
if (!is(snapshot, maybeNewSnapshot)) {
setSnapshot(maybeNewSnapshot);
const lane = requestUpdateLane(fiber);
markRootMutableRead(root, lane);
}
// If the source mutated between render and now,
// there may be state updates already scheduled from the old source.
// Entangle the updates so that they render in the same batch.
markRootEntangled(root, root.mutableReadLanes);
}
}, [getSnapshot, source, subscribe]);
// If we got a new source or subscribe function, re-subscribe in a passive effect.
dispatcher.useEffect(() => {
const handleChange = () => {
const latestGetSnapshot = refs.getSnapshot;
const latestSetSnapshot = refs.setSnapshot;
try {
latestSetSnapshot(latestGetSnapshot(source._source));
// Record a pending mutable source update with the same expiration time.
const lane = requestUpdateLane(fiber);
markRootMutableRead(root, lane);
} catch (error) {
// A selector might throw after a source mutation.
// e.g. it might try to read from a part of the store that no longer exists.
// In this case we should still schedule an update with React.
// Worst case the selector will throw again and then an error boundary will handle it.
latestSetSnapshot(
(() => {
throw error;
}: any),
);
}
};
const unsubscribe = subscribe(source._source, handleChange);
if (__DEV__) {
if (typeof unsubscribe !== 'function') {
console.error(
'Mutable source subscribe function must return an unsubscribe function.',
);
}
}
return unsubscribe;
}, [source, subscribe]);
// If any of the inputs to useMutableSource change, reading is potentially unsafe.
//
// If either the source or the subscription have changed we can't can't trust the update queue.
// Maybe the source changed in a way that the old subscription ignored but the new one depends on.
//
// If the getSnapshot function changed, we also shouldn't rely on the update queue.
// It's possible that the underlying source was mutated between the when the last "change" event fired,
// and when the current render (with the new getSnapshot function) is processed.
//
// In both cases, we need to throw away pending updates (since they are no longer relevant)
// and treat reading from the source as we do in the mount case.
if (
!is(prevGetSnapshot, getSnapshot) ||
!is(prevSource, source) ||
!is(prevSubscribe, subscribe)
) {
// Create a new queue and setState method,
// So if there are interleaved updates, they get pushed to the older queue.
// When this becomes current, the previous queue and dispatch method will be discarded,
// including any interleaving updates that occur.
const newQueue: UpdateQueue<Snapshot, BasicStateAction<Snapshot>> = {
pending: null,
lanes: NoLanes,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: snapshot,
};
newQueue.dispatch = setSnapshot = (dispatchSetState.bind(
null,
currentlyRenderingFiber,
newQueue,
): any);
stateHook.queue = newQueue;
stateHook.baseQueue = null;
snapshot = readFromUnsubscribedMutableSource(root, source, getSnapshot);
stateHook.memoizedState = stateHook.baseState = snapshot;
}
return snapshot;
}
function mountMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
if (!enableUseMutableSource) {
return (undefined: any);
}
const hook = mountWorkInProgressHook();
hook.memoizedState = ({
refs: {
getSnapshot,
setSnapshot: (null: any),
},
source,
subscribe,
}: MutableSourceMemoizedState<Source, Snapshot>);
return useMutableSource(hook, source, getSnapshot, subscribe);
}
function updateMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
if (!enableUseMutableSource) {
return (undefined: any);
}
const hook = updateWorkInProgressHook();
return useMutableSource(hook, source, getSnapshot, subscribe);
}
function mountSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
@@ -3203,7 +2897,6 @@ export const ContextOnlyDispatcher: Dispatcher = {
useDebugValue: throwInvalidHookError,
useDeferredValue: throwInvalidHookError,
useTransition: throwInvalidHookError,
useMutableSource: throwInvalidHookError,
useSyncExternalStore: throwInvalidHookError,
useId: throwInvalidHookError,
};
@@ -3241,7 +2934,6 @@ const HooksDispatcherOnMount: Dispatcher = {
useDebugValue: mountDebugValue,
useDeferredValue: mountDeferredValue,
useTransition: mountTransition,
useMutableSource: mountMutableSource,
useSyncExternalStore: mountSyncExternalStore,
useId: mountId,
};
@@ -3279,7 +2971,6 @@ const HooksDispatcherOnUpdate: Dispatcher = {
useDebugValue: updateDebugValue,
useDeferredValue: updateDeferredValue,
useTransition: updateTransition,
useMutableSource: updateMutableSource,
useSyncExternalStore: updateSyncExternalStore,
useId: updateId,
};
@@ -3317,7 +3008,6 @@ const HooksDispatcherOnRerender: Dispatcher = {
useDebugValue: updateDebugValue,
useDeferredValue: rerenderDeferredValue,
useTransition: rerenderTransition,
useMutableSource: updateMutableSource,
useSyncExternalStore: updateSyncExternalStore,
useId: updateId,
};
@@ -3478,15 +3168,6 @@ if (__DEV__) {
mountHookTypesDev();
return mountTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
mountHookTypesDev();
return mountMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
@@ -3646,15 +3327,6 @@ if (__DEV__) {
updateHookTypesDev();
return mountTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
updateHookTypesDev();
return mountMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
@@ -3818,15 +3490,6 @@ if (__DEV__) {
updateHookTypesDev();
return updateTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
updateHookTypesDev();
return updateMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
@@ -3989,15 +3652,6 @@ if (__DEV__) {
updateHookTypesDev();
return rerenderTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
updateHookTypesDev();
return updateMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
@@ -4174,16 +3828,6 @@ if (__DEV__) {
mountHookTypesDev();
return mountTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
warnInvalidHookAccess();
mountHookTypesDev();
return mountMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
@@ -4371,16 +4015,6 @@ if (__DEV__) {
updateHookTypesDev();
return updateTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
warnInvalidHookAccess();
updateHookTypesDev();
return updateMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
@@ -4568,16 +4202,6 @@ if (__DEV__) {
updateHookTypesDev();
return rerenderTransition();
},
useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
currentHookNameInDev = 'useMutableSource';
warnInvalidHookAccess();
updateHookTypesDev();
return updateMutableSource(source, getSnapshot, subscribe);
},
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,

View File

@@ -299,8 +299,8 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes {
// time it takes to show the final state, which is what they are actually
// waiting for.
//
// For those exceptions where entanglement is semantically important, like
// useMutableSource, we should ensure that there is no partial work at the
// For those exceptions where entanglement is semantically important,
// we should ensure that there is no partial work at the
// time we apply the entanglement.
const entangledLanes = root.entangledLanes;
if (entangledLanes !== NoLanes) {
@@ -622,10 +622,6 @@ export function markRootPinged(root: FiberRoot, pingedLanes: Lanes) {
root.pingedLanes |= root.suspendedLanes & pingedLanes;
}
export function markRootMutableRead(root: FiberRoot, updateLane: Lane) {
root.mutableReadLanes |= updateLane & root.pendingLanes;
}
export function markRootFinished(root: FiberRoot, remainingLanes: Lanes) {
const noLongerPendingLanes = root.pendingLanes & ~remainingLanes;
@@ -636,7 +632,6 @@ export function markRootFinished(root: FiberRoot, remainingLanes: Lanes) {
root.pingedLanes = NoLanes;
root.expiredLanes &= remainingLanes;
root.mutableReadLanes &= remainingLanes;
root.entangledLanes &= remainingLanes;

View File

@@ -97,7 +97,6 @@ import {
findHostInstancesForRefresh,
} from './ReactFiberHotReloading';
import ReactVersion from 'shared/ReactVersion';
export {registerMutableSourceForHydration} from './ReactMutableSource';
export {createPortal} from './ReactPortal';
export {
createComponentSelector,

View File

@@ -17,7 +17,7 @@ import type {RootTag} from './ReactRootTags';
import type {Cache} from './ReactFiberCacheComponent';
import type {Container} from './ReactFiberConfig';
import {noTimeout, supportsHydration} from './ReactFiberConfig';
import {noTimeout} from './ReactFiberConfig';
import {createHostRootFiber} from './ReactFiber';
import {
NoLane,
@@ -72,7 +72,6 @@ function FiberRootNode(
this.suspendedLanes = NoLanes;
this.pingedLanes = NoLanes;
this.expiredLanes = NoLanes;
this.mutableReadLanes = NoLanes;
this.finishedLanes = NoLanes;
this.errorRecoveryDisabledLanes = NoLanes;
@@ -89,10 +88,6 @@ function FiberRootNode(
this.pooledCacheLanes = NoLanes;
}
if (supportsHydration) {
this.mutableSourceEagerHydrationData = null;
}
if (enableSuspenseCallback) {
this.hydrationCallbacks = null;
}

View File

@@ -14,7 +14,6 @@ import type {SuspenseState} from './ReactFiberSuspenseComponent';
import type {Cache} from './ReactFiberCacheComponent';
import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent';
import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource';
import {
ClassComponent,
HostRoot,
@@ -103,7 +102,6 @@ function unwindWork(
popRootTransition(workInProgress, root, renderLanes);
popHostContainer(workInProgress);
popTopLevelLegacyContextObject(workInProgress);
resetMutableSourceWorkInProgressVersions();
const flags = workInProgress.flags;
if (
(flags & ShouldCapture) !== NoFlags &&
@@ -234,7 +232,6 @@ function unwindInterruptedWork(
popRootTransition(interruptedWork, root, renderLanes);
popHostContainer(interruptedWork);
popTopLevelLegacyContextObject(interruptedWork);
resetMutableSourceWorkInProgressVersions();
break;
}
case HostHoistable:

View File

@@ -11,10 +11,6 @@ import type {Source} from 'shared/ReactElementType';
import type {
RefObject,
ReactContext,
MutableSourceSubscribeFn,
MutableSourceGetSnapshotFn,
MutableSourceVersion,
MutableSource,
StartTransitionOptions,
Wakeable,
Usable,
@@ -54,7 +50,6 @@ export type HookType =
| 'useDebugValue'
| 'useDeferredValue'
| 'useTransition'
| 'useMutableSource'
| 'useSyncExternalStore'
| 'useId'
| 'useCacheRefresh'
@@ -237,11 +232,6 @@ type BaseFiberRootProperties = {
context: Object | null,
pendingContext: Object | null,
// Used by useMutableSource hook to avoid tearing during hydration.
mutableSourceEagerHydrationData?: Array<
MutableSource<any> | MutableSourceVersion,
> | null,
// Used to create a linked list that represent all the roots that have
// pending work scheduled on them.
next: FiberRoot | null,
@@ -257,7 +247,6 @@ type BaseFiberRootProperties = {
suspendedLanes: Lanes,
pingedLanes: Lanes,
expiredLanes: Lanes,
mutableReadLanes: Lanes,
errorRecoveryDisabledLanes: Lanes,
finishedLanes: Lanes,
@@ -410,11 +399,6 @@ export type Dispatcher = {
boolean,
(callback: () => void, options?: StartTransitionOptions) => void,
],
useMutableSource<TSource, Snapshot>(
source: MutableSource<TSource>,
getSnapshot: MutableSourceGetSnapshotFn<TSource, Snapshot>,
subscribe: MutableSourceSubscribeFn<TSource, Snapshot>,
): Snapshot,
useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,

View File

@@ -1,108 +0,0 @@
/**
* 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 {MutableSource, MutableSourceVersion} from 'shared/ReactTypes';
import type {FiberRoot} from './ReactInternalTypes';
import {isPrimaryRenderer} from './ReactFiberConfig';
// Work in progress version numbers only apply to a single render,
// and should be reset before starting a new render.
// This tracks which mutable sources need to be reset after a render.
const workInProgressSources: Array<MutableSource<any>> = [];
let rendererSigil;
if (__DEV__) {
// Used to detect multiple renderers using the same mutable source.
rendererSigil = {};
}
export function markSourceAsDirty(mutableSource: MutableSource<any>): void {
workInProgressSources.push(mutableSource);
}
export function resetWorkInProgressVersions(): void {
for (let i = 0; i < workInProgressSources.length; i++) {
const mutableSource = workInProgressSources[i];
if (isPrimaryRenderer) {
mutableSource._workInProgressVersionPrimary = null;
} else {
mutableSource._workInProgressVersionSecondary = null;
}
}
workInProgressSources.length = 0;
}
export function getWorkInProgressVersion(
mutableSource: MutableSource<any>,
): null | MutableSourceVersion {
if (isPrimaryRenderer) {
return mutableSource._workInProgressVersionPrimary;
} else {
return mutableSource._workInProgressVersionSecondary;
}
}
export function setWorkInProgressVersion(
mutableSource: MutableSource<any>,
version: MutableSourceVersion,
): void {
if (isPrimaryRenderer) {
mutableSource._workInProgressVersionPrimary = version;
} else {
mutableSource._workInProgressVersionSecondary = version;
}
workInProgressSources.push(mutableSource);
}
export function warnAboutMultipleRenderersDEV(
mutableSource: MutableSource<any>,
): void {
if (__DEV__) {
if (isPrimaryRenderer) {
if (mutableSource._currentPrimaryRenderer == null) {
mutableSource._currentPrimaryRenderer = rendererSigil;
} else if (mutableSource._currentPrimaryRenderer !== rendererSigil) {
console.error(
'Detected multiple renderers concurrently rendering the ' +
'same mutable source. This is currently unsupported.',
);
}
} else {
if (mutableSource._currentSecondaryRenderer == null) {
mutableSource._currentSecondaryRenderer = rendererSigil;
} else if (mutableSource._currentSecondaryRenderer !== rendererSigil) {
console.error(
'Detected multiple renderers concurrently rendering the ' +
'same mutable source. This is currently unsupported.',
);
}
}
}
}
// Eager reads the version of a mutable source and stores it on the root.
// This ensures that the version used for server rendering matches the one
// that is eventually read during hydration.
// If they don't match there's a potential tear and a full deopt render is required.
export function registerMutableSourceForHydration(
root: FiberRoot,
mutableSource: MutableSource<any>,
): void {
const getVersion = mutableSource._getVersion;
const version = getVersion(mutableSource._source);
// TODO Clear this data once all pending hydration work is finished.
// Retaining it forever may interfere with GC.
if (root.mutableSourceEagerHydrationData == null) {
root.mutableSourceEagerHydrationData = [mutableSource, version];
} else {
root.mutableSourceEagerHydrationData.push(mutableSource, version);
}
}

View File

@@ -1,379 +0,0 @@
/**
* 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.
*
* @emails react-core
*/
'use strict';
let React;
let ReactDOMClient;
let ReactDOMServer;
let Scheduler;
let act;
let createMutableSource;
let useMutableSource;
let waitFor;
let assertLog;
describe('useMutableSourceHydration', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactDOMClient = require('react-dom/client');
ReactDOMServer = require('react-dom/server');
Scheduler = require('scheduler');
act = require('internal-test-utils').act;
// Stable entrypoints export with "unstable_" prefix.
createMutableSource =
React.createMutableSource || React.unstable_createMutableSource;
useMutableSource =
React.useMutableSource || React.unstable_useMutableSource;
const InternalTestUtils = require('internal-test-utils');
waitFor = InternalTestUtils.waitFor;
assertLog = InternalTestUtils.assertLog;
});
const defaultGetSnapshot = source => source.value;
const defaultSubscribe = (source, callback) => source.subscribe(callback);
function createComplexSource(initialValueA, initialValueB) {
const callbacksA = [];
const callbacksB = [];
let revision = 0;
let valueA = initialValueA;
let valueB = initialValueB;
const subscribeHelper = (callbacks, callback) => {
if (callbacks.indexOf(callback) < 0) {
callbacks.push(callback);
}
return () => {
const index = callbacks.indexOf(callback);
if (index >= 0) {
callbacks.splice(index, 1);
}
};
};
return {
subscribeA(callback) {
return subscribeHelper(callbacksA, callback);
},
subscribeB(callback) {
return subscribeHelper(callbacksB, callback);
},
get listenerCountA() {
return callbacksA.length;
},
get listenerCountB() {
return callbacksB.length;
},
set valueA(newValue) {
revision++;
valueA = newValue;
callbacksA.forEach(callback => callback());
},
get valueA() {
return valueA;
},
set valueB(newValue) {
revision++;
valueB = newValue;
callbacksB.forEach(callback => callback());
},
get valueB() {
return valueB;
},
get version() {
return revision;
},
};
}
function createSource(initialValue) {
const callbacks = [];
let revision = 0;
let value = initialValue;
return {
subscribe(callback) {
if (callbacks.indexOf(callback) < 0) {
callbacks.push(callback);
}
return () => {
const index = callbacks.indexOf(callback);
if (index >= 0) {
callbacks.splice(index, 1);
}
};
},
get listenerCount() {
return callbacks.length;
},
set value(newValue) {
revision++;
value = newValue;
callbacks.forEach(callback => callback());
},
get value() {
return value;
},
get version() {
return revision;
},
};
}
function Component({getSnapshot, label, mutableSource, subscribe}) {
const snapshot = useMutableSource(mutableSource, getSnapshot, subscribe);
Scheduler.log(`${label}:${snapshot}`);
return <div>{`${label}:${snapshot}`}</div>;
}
// @gate enableUseMutableSource
it('should render and hydrate', async () => {
const source = createSource('one');
const mutableSource = createMutableSource(source, param => param.version);
function TestComponent() {
return (
<Component
label="only"
getSnapshot={defaultGetSnapshot}
mutableSource={mutableSource}
subscribe={defaultSubscribe}
/>
);
}
const container = document.createElement('div');
document.body.appendChild(container);
const htmlString = ReactDOMServer.renderToString(<TestComponent />);
container.innerHTML = htmlString;
assertLog(['only:one']);
expect(source.listenerCount).toBe(0);
await act(() => {
ReactDOMClient.hydrateRoot(container, <TestComponent />, {
mutableSources: [mutableSource],
});
});
assertLog(['only:one']);
expect(source.listenerCount).toBe(1);
});
// @gate enableUseMutableSource
// @gate enableClientRenderFallbackOnTextMismatch
it('should detect a tear before hydrating a component', async () => {
const source = createSource('one');
const mutableSource = createMutableSource(source, param => param.version);
function TestComponent() {
return (
<Component
label="only"
getSnapshot={defaultGetSnapshot}
mutableSource={mutableSource}
subscribe={defaultSubscribe}
/>
);
}
const container = document.createElement('div');
document.body.appendChild(container);
const htmlString = ReactDOMServer.renderToString(<TestComponent />);
container.innerHTML = htmlString;
assertLog(['only:one']);
expect(source.listenerCount).toBe(0);
await expect(async () => {
await act(() => {
ReactDOMClient.hydrateRoot(container, <TestComponent />, {
mutableSources: [mutableSource],
onRecoverableError(error) {
Scheduler.log('Log error: ' + error.message);
},
});
source.value = 'two';
});
}).toErrorDev(
[
'Warning: Text content did not match. Server: "only:one" Client: "only:two"',
'Warning: An error occurred during hydration. The server HTML was replaced with client content in <div>.',
],
{withoutStack: 1},
);
assertLog([
'only:two',
'only:two',
'Log error: Text content does not match server-rendered HTML.',
'Log error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.',
]);
expect(source.listenerCount).toBe(1);
});
// @gate enableUseMutableSource
it('should detect a tear between hydrating components', async () => {
const source = createSource('one');
const mutableSource = createMutableSource(source, param => param.version);
function TestComponent() {
return (
<>
<Component
label="a"
getSnapshot={defaultGetSnapshot}
mutableSource={mutableSource}
subscribe={defaultSubscribe}
/>
<Component
label="b"
getSnapshot={defaultGetSnapshot}
mutableSource={mutableSource}
subscribe={defaultSubscribe}
/>
</>
);
}
const container = document.createElement('div');
document.body.appendChild(container);
const htmlString = ReactDOMServer.renderToString(<TestComponent />);
container.innerHTML = htmlString;
assertLog(['a:one', 'b:one']);
expect(source.listenerCount).toBe(0);
await expect(async () => {
await act(async () => {
React.startTransition(() => {
ReactDOMClient.hydrateRoot(container, <TestComponent />, {
mutableSources: [mutableSource],
onRecoverableError(error) {
Scheduler.log('Log error: ' + error.message);
},
});
});
await waitFor(['a:one']);
source.value = 'two';
});
}).toErrorDev(
'Warning: An error occurred during hydration. ' +
'The server HTML was replaced with client content in <div>.',
{withoutStack: true},
);
assertLog([
'a:two',
'b:two',
// TODO: Before onRecoverableError, this error was never surfaced to the
// user. The request to file an bug report no longer makes sense.
// However, the experimental useMutableSource API is slated for
// removal, anyway.
'Log error: Cannot read from mutable source during the current ' +
'render without tearing. This may be a bug in React. Please file ' +
'an issue.',
'Log error: There was an error while hydrating. Because the error ' +
'happened outside of a Suspense boundary, the entire root will ' +
'switch to client rendering.',
]);
expect(source.listenerCount).toBe(2);
});
// @gate enableUseMutableSource
it('should detect a tear between hydrating components reading from different parts of a source', async () => {
const source = createComplexSource('a:one', 'b:one');
const mutableSource = createMutableSource(source, param => param.version);
// Subscribe to part of the store.
const getSnapshotA = s => s.valueA;
const subscribeA = (s, callback) => s.subscribeA(callback);
const getSnapshotB = s => s.valueB;
const subscribeB = (s, callback) => s.subscribeB(callback);
const container = document.createElement('div');
document.body.appendChild(container);
const htmlString = ReactDOMServer.renderToString(
<>
<Component
label="0"
getSnapshot={getSnapshotA}
mutableSource={mutableSource}
subscribe={subscribeA}
/>
<Component
label="1"
getSnapshot={getSnapshotB}
mutableSource={mutableSource}
subscribe={subscribeB}
/>
</>,
);
container.innerHTML = htmlString;
assertLog(['0:a:one', '1:b:one']);
await expect(async () => {
await act(async () => {
const fragment = (
<>
<Component
label="0"
getSnapshot={getSnapshotA}
mutableSource={mutableSource}
subscribe={subscribeA}
/>
<Component
label="1"
getSnapshot={getSnapshotB}
mutableSource={mutableSource}
subscribe={subscribeB}
/>
</>
);
React.startTransition(() => {
ReactDOMClient.hydrateRoot(container, fragment, {
mutableSources: [mutableSource],
onRecoverableError(error) {
Scheduler.log('Log error: ' + error.message);
},
});
});
await waitFor(['0:a:one']);
source.valueB = 'b:two';
});
}).toErrorDev(
'Warning: An error occurred during hydration. ' +
'The server HTML was replaced with client content in <div>.',
{withoutStack: true},
);
assertLog([
'0:a:one',
'1:b:two',
// TODO: Before onRecoverableError, this error was never surfaced to the
// user. The request to file an bug report no longer makes sense.
// However, the experimental useMutableSource API is slated for
// removal, anyway.
'Log error: Cannot read from mutable source during the current ' +
'render without tearing. This may be a bug in React. Please file ' +
'an issue.',
'Log error: There was an error while hydrating. Because the error ' +
'happened outside of a Suspense boundary, the entire root will ' +
'switch to client rendering.',
]);
});
});

View File

@@ -10,9 +10,6 @@
import type {Dispatcher} from 'react-reconciler/src/ReactInternalTypes';
import type {
MutableSource,
MutableSourceGetSnapshotFn,
MutableSourceSubscribeFn,
ReactContext,
StartTransitionOptions,
Thenable,
@@ -505,18 +502,6 @@ export function useEffectEvent<Args, Return, F: (...Array<Args>) => Return>(
return throwOnUseEffectEventCall;
}
// TODO Decide on how to implement this hook for server rendering.
// If a mutation occurs during render, consider triggering a Suspense boundary
// and falling back to client rendering.
function useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
resolveCurrentlyRenderingComponent();
return getSnapshot(source._source);
}
function useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
@@ -648,7 +633,6 @@ export const HooksDispatcher: Dispatcher = {
useTransition,
useId,
// Subscriptions are not setup in a server environment.
useMutableSource,
useSyncExternalStore,
};

View File

@@ -87,7 +87,6 @@ export const HooksDispatcher: Dispatcher = {
useImperativeHandle: (unsupportedHook: any),
useEffect: (unsupportedHook: any),
useId,
useMutableSource: (unsupportedHook: any),
useSyncExternalStore: (unsupportedHook: any),
useCacheRefresh(): <T>(?() => T, ?T) => void {
return unsupportedRefresh;

View File

@@ -23,8 +23,6 @@ export {
createContext,
createElement,
createFactory,
createMutableSource,
createMutableSource as unstable_createMutableSource,
createRef,
createServerContext,
use,
@@ -57,8 +55,6 @@ export {
useLayoutEffect,
useInsertionEffect,
useMemo,
useMutableSource,
useMutableSource as unstable_useMutableSource,
experimental_useOptimistic,
useReducer,
useRef,

View File

@@ -45,7 +45,6 @@ export {
createContext,
createElement,
createFactory,
createMutableSource,
createRef,
createServerContext,
use,
@@ -76,7 +75,6 @@ export {
useInsertionEffect,
useLayoutEffect,
useMemo,
useMutableSource,
experimental_useOptimistic,
useSyncExternalStore,
useReducer,

View File

@@ -22,8 +22,6 @@ export {
cloneElement,
createContext,
createElement,
createMutableSource,
createMutableSource as unstable_createMutableSource,
createRef,
createServerContext,
use,
@@ -55,8 +53,6 @@ export {
useInsertionEffect,
useLayoutEffect,
useMemo,
useMutableSource,
useMutableSource as unstable_useMutableSource,
experimental_useOptimistic,
useReducer,
useRef,

View File

@@ -48,7 +48,6 @@ import {
useInsertionEffect,
useLayoutEffect,
useMemo,
useMutableSource,
useSyncExternalStore,
useReducer,
useRef,
@@ -67,7 +66,6 @@ import {
cloneElementWithValidation,
} from './ReactElementValidator';
import {createServerContext} from './ReactServerContext';
import {createMutableSource} from './ReactMutableSource';
import ReactSharedInternals from './ReactSharedInternals';
import {startTransition} from './ReactStartTransition';
import {act} from './ReactAct';
@@ -93,7 +91,6 @@ const Children = {
export {
Children,
createMutableSource,
createRef,
Component,
PureComponent,
@@ -112,7 +109,6 @@ export {
useInsertionEffect,
useLayoutEffect,
useMemo,
useMutableSource,
useOptimistic as experimental_useOptimistic,
useSyncExternalStore,
useReducer,

View File

@@ -9,9 +9,6 @@
import type {Dispatcher} from 'react-reconciler/src/ReactInternalTypes';
import type {
MutableSource,
MutableSourceGetSnapshotFn,
MutableSourceSubscribeFn,
ReactContext,
StartTransitionOptions,
Usable,
@@ -194,15 +191,6 @@ export function useId(): string {
return dispatcher.useId();
}
export function useMutableSource<Source, Snapshot>(
source: MutableSource<Source>,
getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,
subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {
const dispatcher = resolveDispatcher();
return dispatcher.useMutableSource(source, getSnapshot, subscribe);
}
export function useSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,

View File

@@ -1,34 +0,0 @@
/**
* 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 {MutableSource, MutableSourceGetVersionFn} from 'shared/ReactTypes';
export function createMutableSource<Source: $NonMaybeType<mixed>>(
source: Source,
getVersion: MutableSourceGetVersionFn,
): MutableSource<Source> {
const mutableSource: MutableSource<Source> = {
_getVersion: getVersion,
_source: source,
_workInProgressVersionPrimary: null,
_workInProgressVersionSecondary: null,
};
if (__DEV__) {
mutableSource._currentPrimaryRenderer = null;
mutableSource._currentSecondaryRenderer = null;
// Used to detect side effects that update a mutable source during render.
// See https://github.com/facebook/react/issues/19948
mutableSource._currentlyRenderingFiber = null;
mutableSource._initialVersionAsOfFirstRender = null;
}
return mutableSource;
}

View File

@@ -32,9 +32,6 @@ export const enableComponentStackLocations = true;
// TODO: Finish rolling out in www
export const enableClientRenderFallbackOnTextMismatch = true;
// Recoil still uses useMutableSource in www, need to delete
export const enableUseMutableSource = false;
// Not sure if www still uses this. We don't have a replacement but whatever we
// replace it with will likely be different than what's already there, so we
// probably should just delete it as long as nothing in www relies on it.

View File

@@ -7,8 +7,6 @@
* @flow
*/
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
export type ReactNode =
| React$Element<any>
| ReactPortal
@@ -117,56 +115,6 @@ export type ReactScopeInstance = {
getChildContextValues: <T>(context: ReactContext<T>) => Array<T>,
};
// Mutable source version can be anything (e.g. number, string, immutable data structure)
// so long as it changes every time any part of the source changes.
export type MutableSourceVersion = $NonMaybeType<mixed>;
export type MutableSourceGetSnapshotFn<
Source: $NonMaybeType<mixed>,
Snapshot,
> = (source: Source) => Snapshot;
export type MutableSourceSubscribeFn<Source: $NonMaybeType<mixed>, Snapshot> = (
source: Source,
callback: (snapshot: Snapshot) => void,
) => () => void;
export type MutableSourceGetVersionFn = (
source: $NonMaybeType<mixed>,
) => MutableSourceVersion;
export type MutableSource<Source: $NonMaybeType<mixed>> = {
_source: Source,
_getVersion: MutableSourceGetVersionFn,
// Tracks the version of this source at the time it was most recently read.
// Used to determine if a source is safe to read from before it has been subscribed to.
// Version number is only used during mount,
// since the mechanism for determining safety after subscription is expiration time.
//
// As a workaround to support multiple concurrent renderers,
// we categorize some renderers as primary and others as secondary.
// We only expect there to be two concurrent renderers at most:
// React Native (primary) and Fabric (secondary);
// React DOM (primary) and React ART (secondary).
// Secondary renderers store their context values on separate fields.
// We use the same approach for Context.
_workInProgressVersionPrimary: null | MutableSourceVersion,
_workInProgressVersionSecondary: null | MutableSourceVersion,
// DEV only
// Used to detect multiple renderers using the same mutable source.
_currentPrimaryRenderer?: Object | null,
_currentSecondaryRenderer?: Object | null,
// DEV only
// Used to detect side effects that update a mutable source during render.
// See https://github.com/facebook/react/issues/19948
_currentlyRenderingFiber?: Fiber | null,
_initialVersionAsOfFirstRender?: MutableSourceVersion | null,
};
// 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 {

View File

@@ -74,8 +74,6 @@ export const enableCustomElementPropertySupport = false;
export const consoleManagedByDevToolsDuringStrictMode = false;
export const enableServerContext = true;
export const enableUseMutableSource = true;
export const enableTransitionTracing = false;
export const enableFloat = true;

View File

@@ -60,7 +60,6 @@ export const enableCustomElementPropertySupport = false;
export const consoleManagedByDevToolsDuringStrictMode = false;
export const enableServerContext = true;
export const enableUseMutableSource = false;
export const enableTransitionTracing = false;

View File

@@ -60,7 +60,6 @@ export const enableCustomElementPropertySupport = false;
export const consoleManagedByDevToolsDuringStrictMode = false;
export const enableServerContext = true;
export const enableUseMutableSource = false;
export const enableTransitionTracing = false;

View File

@@ -58,7 +58,6 @@ export const allowConcurrentByDefault = true;
export const consoleManagedByDevToolsDuringStrictMode = false;
export const enableServerContext = true;
export const enableUseMutableSource = false;
export const enableTransitionTracing = false;

View File

@@ -61,9 +61,6 @@ export const enableCustomElementPropertySupport = false;
export const consoleManagedByDevToolsDuringStrictMode = false;
export const enableServerContext = true;
// Some www surfaces are still using this. Remove once they have been migrated.
export const enableUseMutableSource = true;
export const enableTransitionTracing = false;
export const enableFloat = true;

View File

@@ -100,9 +100,6 @@ export const allowConcurrentByDefault = true;
export const consoleManagedByDevToolsDuringStrictMode = true;
export const enableServerContext = true;
// Some www surfaces are still using this. Remove once they have been migrated.
export const enableUseMutableSource = true;
export const useModernStrictMode = false;
export const enableFizzExternalRuntime = true;