Skip to content

Commit

Permalink
Call and Return components should use ReactElement (#11834)
Browse files Browse the repository at this point in the history
* Call and Return components should use ReactElement

ReactChildFiber contains lots of branches that do the same thing for
different child types. We can unify them by having more child types be
ReactElements. This requires that the `type` and `key` fields are
sufficient to determine the identity of the child.

The main benefit is decreased file size, especially as we add more
component types, like context providers and consumers.

This updates Call and Return components to use ReactElement. Portals are
left alone for now because their identity includes the host instance.

* Move server render invariant for call and return types

* Sort ReactElement type checks by most likely

* Performance timeline should skip over call components

Don't think these were intentionally omitted from the blacklist of
component types.

I went ahead and updated getComponentName to include special types, even
though I don't think they're used anywhere right now.

* Remove surrounding brackets from internal display names
  • Loading branch information
acdlite authored Dec 12, 2017
1 parent 73265fc commit b77b123
Show file tree
Hide file tree
Showing 12 changed files with 195 additions and 366 deletions.
45 changes: 29 additions & 16 deletions packages/react-call-return/src/ReactCallReturn.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,33 @@
* @flow
*/

import {REACT_CALL_TYPE, REACT_RETURN_TYPE} from 'shared/ReactSymbols';
import {
REACT_CALL_TYPE,
REACT_RETURN_TYPE,
REACT_ELEMENT_TYPE,
} from 'shared/ReactSymbols';

import type {ReactCall, ReactNodeList, ReactReturn} from 'shared/ReactTypes';

type CallHandler<T> = (props: T, returns: Array<mixed>) => ReactNodeList;
type CallHandler<T, V> = (props: T, returns: Array<V>) => ReactNodeList;

export function unstable_createCall<T>(
children: mixed,
handler: CallHandler<T>,
export function unstable_createCall<T, V>(
children: ReactNodeList,
handler: CallHandler<T, V>,
props: T,
key: ?string = null,
): ReactCall {
): ReactCall<V> {
const call = {
// This tag allow us to uniquely identify this as a React Call
$$typeof: REACT_CALL_TYPE,
$$typeof: REACT_ELEMENT_TYPE,
type: REACT_CALL_TYPE,
key: key == null ? null : '' + key,
children: children,
handler: handler,
props: props,
ref: null,
props: {
props,
handler,
children: children,
},
};

if (__DEV__) {
Expand All @@ -39,11 +47,16 @@ export function unstable_createCall<T>(
return call;
}

export function unstable_createReturn(value: mixed): ReactReturn {
export function unstable_createReturn<V>(value: V): ReactReturn<V> {
const returnNode = {
// This tag allow us to uniquely identify this as a React Return
$$typeof: REACT_RETURN_TYPE,
value: value,
// This tag allow us to uniquely identify this as a React Call
$$typeof: REACT_ELEMENT_TYPE,
type: REACT_RETURN_TYPE,
key: null,
ref: null,
props: {
value,
},
};

if (__DEV__) {
Expand All @@ -63,7 +76,7 @@ export function unstable_isCall(object: mixed): boolean {
return (
typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_CALL_TYPE
object.type === REACT_CALL_TYPE
);
}

Expand All @@ -74,7 +87,7 @@ export function unstable_isReturn(object: mixed): boolean {
return (
typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_RETURN_TYPE
object.type === REACT_RETURN_TYPE
);
}

Expand Down
58 changes: 31 additions & 27 deletions packages/react-dom/src/server/ReactPartialRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -621,11 +621,6 @@ class ReactDOMServerRenderer {
'Portals are not currently supported by the server renderer. ' +
'Render them conditionally so that they only appear on the client render.',
);
invariant(
$$typeof !== REACT_CALL_TYPE && $$typeof !== REACT_RETURN_TYPE,
'The experimental Call and Return types are not currently ' +
'supported by the server renderer.',
);
// Catch-all to prevent an infinite loop if React.Children.toArray() supports some new type.
invariant(
false,
Expand All @@ -647,28 +642,37 @@ class ReactDOMServerRenderer {
}
this.stack.push(frame);
return '';
} else if (
((nextChild: any): ReactElement).type === REACT_FRAGMENT_TYPE
) {
const nextChildren = toArray(
((nextChild: any): ReactElement).props.children,
);
const frame: Frame = {
domNamespace: parentNamespace,
children: nextChildren,
childIndex: 0,
context: context,
footer: '',
};
if (__DEV__) {
((frame: any): FrameDev).debugElementStack = [];
}
this.stack.push(frame);
return '';
} else {
// Safe because we just checked it's an element.
const nextElement = ((nextChild: any): ReactElement);
return this.renderDOM(nextElement, context, parentNamespace);
}
// Safe because we just checked it's an element.
const nextElement = ((nextChild: any): ReactElement);
const elementType = nextElement.type;
switch (elementType) {
case REACT_FRAGMENT_TYPE:
const nextChildren = toArray(
((nextChild: any): ReactElement).props.children,
);
const frame: Frame = {
domNamespace: parentNamespace,
children: nextChildren,
childIndex: 0,
context: context,
footer: '',
};
if (__DEV__) {
((frame: any): FrameDev).debugElementStack = [];
}
this.stack.push(frame);
return '';
case REACT_CALL_TYPE:
case REACT_RETURN_TYPE:
invariant(
false,
'The experimental Call and Return types are not currently ' +
'supported by the server renderer.',
);
// eslint-disable-next-line-no-fallthrough
default:
return this.renderDOM(nextElement, context, parentNamespace);
}
}
}
Expand Down
Loading

0 comments on commit b77b123

Please sign in to comment.