Skip to content

Commit

Permalink
Fix react-is memo and lazy type checks (#17278)
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian Vaughn committed Nov 5, 2019
1 parent 0f3838a commit 053cf0f
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 15 deletions.
4 changes: 2 additions & 2 deletions packages/react-is/src/ReactIs.js
Expand Up @@ -48,14 +48,14 @@ export function typeOf(object: any) {
switch ($$typeofType) {
case REACT_CONTEXT_TYPE:
case REACT_FORWARD_REF_TYPE:
case REACT_LAZY_TYPE:
case REACT_MEMO_TYPE:
case REACT_PROVIDER_TYPE:
return $$typeofType;
default:
return $$typeof;
}
}
case REACT_LAZY_TYPE:
case REACT_MEMO_TYPE:
case REACT_PORTAL_TYPE:
return $$typeof;
}
Expand Down
26 changes: 18 additions & 8 deletions packages/react-is/src/__tests__/ReactIs-test.js
Expand Up @@ -71,6 +71,7 @@ describe('ReactIs', () => {

it('should identify context consumers', () => {
const Context = React.createContext(false);
expect(ReactIs.isValidElementType(Context.Consumer)).toBe(true);
expect(ReactIs.typeOf(<Context.Consumer />)).toBe(ReactIs.ContextConsumer);
expect(ReactIs.isContextConsumer(<Context.Consumer />)).toBe(true);
expect(ReactIs.isContextConsumer(<Context.Provider />)).toBe(false);
Expand All @@ -79,6 +80,7 @@ describe('ReactIs', () => {

it('should identify context providers', () => {
const Context = React.createContext(false);
expect(ReactIs.isValidElementType(Context.Provider)).toBe(true);
expect(ReactIs.typeOf(<Context.Provider />)).toBe(ReactIs.ContextProvider);
expect(ReactIs.isContextProvider(<Context.Provider />)).toBe(true);
expect(ReactIs.isContextProvider(<Context.Consumer />)).toBe(false);
Expand Down Expand Up @@ -106,13 +108,15 @@ describe('ReactIs', () => {

it('should identify ref forwarding component', () => {
const RefForwardingComponent = React.forwardRef((props, ref) => null);
expect(ReactIs.isValidElementType(RefForwardingComponent)).toBe(true);
expect(ReactIs.typeOf(<RefForwardingComponent />)).toBe(ReactIs.ForwardRef);
expect(ReactIs.isForwardRef(<RefForwardingComponent />)).toBe(true);
expect(ReactIs.isForwardRef({type: ReactIs.StrictMode})).toBe(false);
expect(ReactIs.isForwardRef(<div />)).toBe(false);
});

it('should identify fragments', () => {
expect(ReactIs.isValidElementType(React.Fragment)).toBe(true);
expect(ReactIs.typeOf(<React.Fragment />)).toBe(ReactIs.Fragment);
expect(ReactIs.isFragment(<React.Fragment />)).toBe(true);
expect(ReactIs.isFragment({type: ReactIs.Fragment})).toBe(false);
Expand All @@ -124,35 +128,40 @@ describe('ReactIs', () => {
it('should identify portals', () => {
const div = document.createElement('div');
const portal = ReactDOM.createPortal(<div />, div);
expect(ReactIs.isValidElementType(portal)).toBe(false);
expect(ReactIs.typeOf(portal)).toBe(ReactIs.Portal);
expect(ReactIs.isPortal(portal)).toBe(true);
expect(ReactIs.isPortal(div)).toBe(false);
});

it('should identify memo', () => {
const Component = () => React.createElement('div');
const memoized = React.memo(Component);
expect(ReactIs.typeOf(memoized)).toBe(ReactIs.Memo);
expect(ReactIs.isMemo(memoized)).toBe(true);
expect(ReactIs.isMemo(Component)).toBe(false);
const Memoized = React.memo(Component);
expect(ReactIs.isValidElementType(Memoized)).toBe(true);
expect(ReactIs.typeOf(<Memoized />)).toBe(ReactIs.Memo);
expect(ReactIs.isMemo(<Memoized />)).toBe(true);
expect(ReactIs.isMemo(<Component />)).toBe(false);
});

it('should identify lazy', () => {
const Component = () => React.createElement('div');
const lazyComponent = React.lazy(() => Component);
expect(ReactIs.typeOf(lazyComponent)).toBe(ReactIs.Lazy);
expect(ReactIs.isLazy(lazyComponent)).toBe(true);
expect(ReactIs.isLazy(Component)).toBe(false);
const LazyComponent = React.lazy(() => Component);
expect(ReactIs.isValidElementType(LazyComponent)).toBe(true);
expect(ReactIs.typeOf(<LazyComponent />)).toBe(ReactIs.Lazy);
expect(ReactIs.isLazy(<LazyComponent />)).toBe(true);
expect(ReactIs.isLazy(<Component />)).toBe(false);
});

it('should identify strict mode', () => {
expect(ReactIs.isValidElementType(React.StrictMode)).toBe(true);
expect(ReactIs.typeOf(<React.StrictMode />)).toBe(ReactIs.StrictMode);
expect(ReactIs.isStrictMode(<React.StrictMode />)).toBe(true);
expect(ReactIs.isStrictMode({type: ReactIs.StrictMode})).toBe(false);
expect(ReactIs.isStrictMode(<div />)).toBe(false);
});

it('should identify suspense', () => {
expect(ReactIs.isValidElementType(React.Suspense)).toBe(true);
expect(ReactIs.typeOf(<React.Suspense />)).toBe(ReactIs.Suspense);
expect(ReactIs.isSuspense(<React.Suspense />)).toBe(true);
expect(ReactIs.isSuspense({type: ReactIs.Suspense})).toBe(false);
Expand All @@ -161,6 +170,7 @@ describe('ReactIs', () => {
});

it('should identify profile root', () => {
expect(ReactIs.isValidElementType(React.Profiler)).toBe(true);
expect(
ReactIs.typeOf(<React.Profiler id="foo" onRender={jest.fn()} />),
).toBe(ReactIs.Profiler);
Expand Down
10 changes: 5 additions & 5 deletions packages/react-test-renderer/src/ReactShallowRenderer.js
Expand Up @@ -542,7 +542,7 @@ class ReactShallowRenderer {
);
invariant(
isForwardRef(element) ||
(typeof element.type === 'function' || isMemo(element.type)),
(typeof element.type === 'function' || isMemo(element)),
'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
'components, but the provided element type was `%s`.',
Array.isArray(element.type)
Expand All @@ -559,15 +559,15 @@ class ReactShallowRenderer {
this._reset();
}

const elementType = isMemo(element.type) ? element.type.type : element.type;
const elementType = isMemo(element) ? element.type.type : element.type;
const previousElement = this._element;

this._rendering = true;
this._element = element;
this._context = getMaskedContext(elementType.contextTypes, context);

// Inner memo component props aren't currently validated in createElement.
if (isMemo(element.type) && elementType.propTypes) {
if (isMemo(element) && elementType.propTypes) {
currentlyValidatingElement = element;
checkPropTypes(
elementType.propTypes,
Expand Down Expand Up @@ -618,7 +618,7 @@ class ReactShallowRenderer {
this._mountClassComponent(elementType, element, this._context);
} else {
let shouldRender = true;
if (isMemo(element.type) && previousElement !== null) {
if (isMemo(element) && previousElement !== null) {
// This is a Memo component that is being re-rendered.
const compare = element.type.compare || shallowEqual;
if (compare(previousElement.props, element.props)) {
Expand Down Expand Up @@ -807,7 +807,7 @@ function getDisplayName(element) {
} else if (typeof element.type === 'string') {
return element.type;
} else {
const elementType = isMemo(element.type) ? element.type.type : element.type;
const elementType = isMemo(element) ? element.type.type : element.type;
return elementType.displayName || elementType.name || 'Unknown';
}
}
Expand Down

0 comments on commit 053cf0f

Please sign in to comment.