Skip to content

Commit

Permalink
Error if refs are passed in server components or to client components
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage committed Oct 8, 2020
1 parent 6f6f032 commit 26f9593
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 8 deletions.
15 changes: 11 additions & 4 deletions packages/react-client/src/__tests__/ReactFlight-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,15 @@ describe('ReactFlight', () => {
return <div foo={Symbol('foo')} />;
}

const ref = React.createRef();
function RefProp() {
return <div ref={ref} />;
}

const event = ReactNoopFlightServer.render(<EventHandlerProp />);
const fn = ReactNoopFlightServer.render(<FunctionProp />);
const symbol = ReactNoopFlightServer.render(<SymbolProp />);
const refs = ReactNoopFlightServer.render(<RefProp />);

function Client({transport}) {
return ReactNoopFlightClient.read(transport);
Expand All @@ -185,6 +191,9 @@ describe('ReactFlight', () => {
<ErrorBoundary expectedMessage="Symbol values (foo) cannot be passed to client components.">
<Client transport={symbol} />
</ErrorBoundary>
<ErrorBoundary expectedMessage="Refs cannot be used in server components, nor passed to client components.">
<Client transport={refs} />
</ErrorBoundary>
</>,
);
});
Expand Down Expand Up @@ -217,10 +226,8 @@ describe('ReactFlight', () => {
);
});

it('should NOT warn in DEV for key/ref getters', () => {
const transport = ReactNoopFlightServer.render(
<div key="a" ref={() => {}} />,
);
it('should NOT warn in DEV for key getters', () => {
const transport = ReactNoopFlightServer.render(<div key="a" />);
act(() => {
ReactNoop.render(ReactNoopFlightClient.read(transport));
});
Expand Down
16 changes: 14 additions & 2 deletions packages/react-server/src/ReactFlightServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,15 @@ export function createRequest(
function attemptResolveElement(element: React$Element<any>): ReactModel {
const type = element.type;
const props = element.props;
if (element.ref !== null && element.ref !== undefined) {
// When the ref moves to the regular props object this will implicitly
// throw for functions. We could probably relax it to a DEV warning for other
// cases.
invariant(
false,
'Refs cannot be used in server components, nor passed to client components.',
);
}
if (typeof type === 'function') {
// This is a server-side component.
return type(props);
Expand Down Expand Up @@ -153,7 +162,7 @@ function attemptResolveElement(element: React$Element<any>): ReactModel {
}
}
}
invariant(false, 'Unsupported type.');
invariant(false, 'Unsupported server component type: %s', describeValueForErrorMessage(type));
}

function pingSegment(request: Request, segment: Segment): void {
Expand Down Expand Up @@ -222,7 +231,10 @@ function isSimpleObject(object): boolean {
return false;
}
if (!descriptor.enumerable) {
if ((names[i] === 'key' || names[i] === 'ref') && typeof descriptor.get === 'function') {
if (
(names[i] === 'key' || names[i] === 'ref') &&
typeof descriptor.get === 'function'
) {
// React adds key and ref getters to props objects to issue warnings.
// Those getters will not be transferred to the client, but that's ok,
// so we'll special case them.
Expand Down
5 changes: 3 additions & 2 deletions scripts/error-codes/codes.json
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@
"348": "ensureListeningTo(): received a container that was not an element node. This is likely a bug in React.",
"349": "Expected a work-in-progress root. This is a bug in React. Please file an issue.",
"350": "Cannot read from mutable source during the current render without tearing. This is a bug in React. Please file an issue.",
"351": "Unsupported type.",
"351": "Unsupported server component type: %s",
"352": "React Blocks (and Lazy Components) are expected to be replaced by a compiler on the server. Try configuring your compiler set up and avoid using React.lazy inside of Blocks.",
"353": "A server block should never encode any other slots. This is a bug in React.",
"354": "getInspectorDataForViewAtPoint() is not available in production.",
Expand All @@ -366,5 +366,6 @@
"375": "Functions cannot be passed directly to client components because they're not serializable. Remove %s (%s) from this object, or avoid the entire object: %s",
"376": "Symbol values (%s) cannot be passed to client components. Remove %s from this object, or avoid the entire object: %s",
"377": "BigInt (%s) is not yet supported in client component props. Remove %s from this object or use a plain number instead: %s",
"378": "Type %s is not supported in client component props. Remove %s from this object, or avoid the entire object: %s"
"378": "Type %s is not supported in client component props. Remove %s from this object, or avoid the entire object: %s",
"379": "Refs cannot be used in server components, nor passed to client components."
}

0 comments on commit 26f9593

Please sign in to comment.