Skip to content

Commit

Permalink
useMutableSource hook
Browse files Browse the repository at this point in the history
useMutableSource() enables React components to safely read from a mutable external source in Concurrent Mode. This API will detect mutations that occur during a render to avoid tearing. It will also automatically schedule updates when the source is mutated
  • Loading branch information
Brian Vaughn committed Feb 7, 2020
1 parent d1bfdfb commit bd870a6
Show file tree
Hide file tree
Showing 11 changed files with 736 additions and 2 deletions.
24 changes: 24 additions & 0 deletions packages/react-debug-tools/src/ReactDebugHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import type {
ReactEventResponder,
ReactEventResponderListener,
} from 'shared/ReactTypes';
import type {
MutableSource,
MutableSourceHookConfig,
} from 'shared/ReactMutableSource';
import type {Fiber} from 'react-reconciler/src/ReactFiber';
import type {Hook, TimeoutConfig} from 'react-reconciler/src/ReactFiberHooks';
import type {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactFiberHooks';
Expand Down Expand Up @@ -67,6 +71,14 @@ function getPrimitiveStackCache(): Map<string, Array<any>> {
Dispatcher.useDebugValue(null);
Dispatcher.useCallback(() => {});
Dispatcher.useMemo(() => null);
Dispatcher.useMutableSource(
{},
{
getVersion: () => null,
getSnapshot: () => null,
subscribe: () => () => {},
},
);
} finally {
readHookLog = hookLog;
hookLog = [];
Expand Down Expand Up @@ -224,6 +236,17 @@ function useMemo<T>(
return value;
}

function useMutableSource<S>(
source: MutableSource,
config: MutableSourceHookConfig<S>,
): S {
const hook = nextHook();
const getSnapshot = config.getSnapshot;
const value = hook !== null ? hook.memoizedState.snapshot : getSnapshot();
hookLog.push({primitive: 'MutableSource', stackError: new Error(), value});
return value;
}

function useResponder(
responder: ReactEventResponder<any, any>,
listenerProps: Object,
Expand Down Expand Up @@ -276,6 +299,7 @@ const Dispatcher: DispatcherType = {
useState,
useResponder,
useTransition,
useMutableSource,
useDeferredValue,
};

Expand Down
15 changes: 15 additions & 0 deletions packages/react-dom/src/server/ReactPartialRendererHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import type {
ReactContext,
ReactEventResponderListener,
} from 'shared/ReactTypes';
import type {
MutableSource,
MutableSourceHookConfig,
} from 'shared/ReactMutableSource';
import type {SuspenseConfig} from 'react-reconciler/src/ReactFiberSuspenseConfig';
import {validateContextBounds} from './ReactPartialRendererContext';

Expand Down Expand Up @@ -459,6 +463,15 @@ function useResponder(responder, props): ReactEventResponderListener<any, any> {
};
}

function useMutableSource<S>(
source: MutableSource,
config: MutableSourceHookConfig<S>,
): S {
resolveCurrentlyRenderingComponent();
const getSnapshot = config.getSnapshot;
return getSnapshot();
}

function useDeferredValue<T>(value: T, config: TimeoutConfig | null | void): T {
resolveCurrentlyRenderingComponent();
return value;
Expand Down Expand Up @@ -500,4 +513,6 @@ export const Dispatcher: DispatcherType = {
useResponder,
useDeferredValue,
useTransition,
// Subscriptions are not setup in a server environment.
useMutableSource,
};

0 comments on commit bd870a6

Please sign in to comment.