Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Shim commonly used Hooks that are safe
  • Loading branch information
gaearon committed Aug 27, 2020
commit 59d2ef5ae2c6c8d103bf6ec37f1722b8e13ecf94
38 changes: 38 additions & 0 deletions packages/react-server/src/ReactFlightServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* @flow
*/

import type {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactInternalTypes';
import type {
Destination,
Chunk,
Expand Down Expand Up @@ -46,6 +47,7 @@ import {
} from 'shared/ReactSymbols';

import * as React from 'react';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import invariant from 'shared/invariant';

type ReactJSONValue =
Expand Down Expand Up @@ -85,6 +87,8 @@ export type Request = {
toJSON: (key: string, value: ReactModel) => ReactJSONValue,
};

const ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;

export function createRequest(
model: ReactModel,
destination: Destination,
Expand Down Expand Up @@ -269,9 +273,11 @@ export function resolveModelToJSON(
value !== null &&
value.$$typeof === REACT_ELEMENT_TYPE
) {
const prevDispatcher = ReactCurrentDispatcher.current;
// TODO: Concatenate keys of parents onto children.
const element: React$Element<any> = (value: any);
try {
ReactCurrentDispatcher.current = Dispatcher;
// Attempt to render the server component.
value = attemptResolveElement(element);
} catch (x) {
Expand All @@ -286,6 +292,8 @@ export function resolveModelToJSON(
// Something errored. Don't bother encoding anything up to here.
throw x;
}
} finally {
ReactCurrentDispatcher.current = prevDispatcher;
}
}

Expand Down Expand Up @@ -411,3 +419,33 @@ export function startFlowing(request: Request): void {
request.flowing = true;
flushCompletedChunks(request);
}

function unsupportedHook(): void {
invariant(false, 'This Hook is not supported in Server Components.');
}

const Dispatcher: DispatcherType = {
useMemo<T>(nextCreate: () => T): T {
return nextCreate();
},
useCallback<T>(callback: T): T {
return callback;
},
useDebugValue(): void {},
useDeferredValue<T>(value: T): T {
return value;
},
useTransition(): [(callback: () => void) => void, boolean] {
return [false, () => {}];
},
readContext: unsupportedHook,
useContext: unsupportedHook,
useReducer: unsupportedHook,
useRef: unsupportedHook,
useState: unsupportedHook,
useLayoutEffect: unsupportedHook,
useImperativeHandle: unsupportedHook,
useEffect: unsupportedHook,
useOpaqueIdentifier: unsupportedHook,
useMutableSource: unsupportedHook,
};
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,33 @@ describe('ReactFlightDOMRelay', () => {
},
});
});

it('can handle a subset of Hooks', () => {
const {useMemo, useCallback} = React;
function Inner({x}) {
const foo = useMemo(() => x + x, [x]);
const bar = useCallback(() => 10 + foo, [foo]);
return bar();
}

function Foo() {
return {
bar: <Inner x={2} />,
};
}
const transport = [];
ReactDOMFlightRelayServer.render(
{
foo: <Foo />,
},
transport,
);

const model = readThrough(transport);
expect(model).toEqual({
foo: {
bar: 14,
},
});
});
});
3 changes: 2 additions & 1 deletion scripts/error-codes/codes.json
Original file line number Diff line number Diff line change
Expand Up @@ -360,5 +360,6 @@
"369": "ReactDOM.createEventHandle: setter called on an invalid target. Provide a valid EventTarget or an element managed by React.",
"370": "ReactDOM.createEventHandle: setter called with an invalid callback. The callback must be a function.",
"371": "Text string must be rendered within a <Text> component.\n\nText: %s",
"372": "Cannot call unstable_createEventHandle with \"%s\", as it is not an event known to React."
"372": "Cannot call unstable_createEventHandle with \"%s\", as it is not an event known to React.",
"373": "This Hook is not supported in Server Components."
}