Skip to content

Commit 053cf0f

Browse files
author
Brian Vaughn
authored
Fix react-is memo and lazy type checks (#17278)
1 parent 0f3838a commit 053cf0f

File tree

3 files changed

+25
-15
lines changed

3 files changed

+25
-15
lines changed

packages/react-is/src/ReactIs.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ export function typeOf(object: any) {
4848
switch ($$typeofType) {
4949
case REACT_CONTEXT_TYPE:
5050
case REACT_FORWARD_REF_TYPE:
51+
case REACT_LAZY_TYPE:
52+
case REACT_MEMO_TYPE:
5153
case REACT_PROVIDER_TYPE:
5254
return $$typeofType;
5355
default:
5456
return $$typeof;
5557
}
5658
}
57-
case REACT_LAZY_TYPE:
58-
case REACT_MEMO_TYPE:
5959
case REACT_PORTAL_TYPE:
6060
return $$typeof;
6161
}

packages/react-is/src/__tests__/ReactIs-test.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ describe('ReactIs', () => {
7171

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

8081
it('should identify context providers', () => {
8182
const Context = React.createContext(false);
83+
expect(ReactIs.isValidElementType(Context.Provider)).toBe(true);
8284
expect(ReactIs.typeOf(<Context.Provider />)).toBe(ReactIs.ContextProvider);
8385
expect(ReactIs.isContextProvider(<Context.Provider />)).toBe(true);
8486
expect(ReactIs.isContextProvider(<Context.Consumer />)).toBe(false);
@@ -106,13 +108,15 @@ describe('ReactIs', () => {
106108

107109
it('should identify ref forwarding component', () => {
108110
const RefForwardingComponent = React.forwardRef((props, ref) => null);
111+
expect(ReactIs.isValidElementType(RefForwardingComponent)).toBe(true);
109112
expect(ReactIs.typeOf(<RefForwardingComponent />)).toBe(ReactIs.ForwardRef);
110113
expect(ReactIs.isForwardRef(<RefForwardingComponent />)).toBe(true);
111114
expect(ReactIs.isForwardRef({type: ReactIs.StrictMode})).toBe(false);
112115
expect(ReactIs.isForwardRef(<div />)).toBe(false);
113116
});
114117

115118
it('should identify fragments', () => {
119+
expect(ReactIs.isValidElementType(React.Fragment)).toBe(true);
116120
expect(ReactIs.typeOf(<React.Fragment />)).toBe(ReactIs.Fragment);
117121
expect(ReactIs.isFragment(<React.Fragment />)).toBe(true);
118122
expect(ReactIs.isFragment({type: ReactIs.Fragment})).toBe(false);
@@ -124,35 +128,40 @@ describe('ReactIs', () => {
124128
it('should identify portals', () => {
125129
const div = document.createElement('div');
126130
const portal = ReactDOM.createPortal(<div />, div);
131+
expect(ReactIs.isValidElementType(portal)).toBe(false);
127132
expect(ReactIs.typeOf(portal)).toBe(ReactIs.Portal);
128133
expect(ReactIs.isPortal(portal)).toBe(true);
129134
expect(ReactIs.isPortal(div)).toBe(false);
130135
});
131136

132137
it('should identify memo', () => {
133138
const Component = () => React.createElement('div');
134-
const memoized = React.memo(Component);
135-
expect(ReactIs.typeOf(memoized)).toBe(ReactIs.Memo);
136-
expect(ReactIs.isMemo(memoized)).toBe(true);
137-
expect(ReactIs.isMemo(Component)).toBe(false);
139+
const Memoized = React.memo(Component);
140+
expect(ReactIs.isValidElementType(Memoized)).toBe(true);
141+
expect(ReactIs.typeOf(<Memoized />)).toBe(ReactIs.Memo);
142+
expect(ReactIs.isMemo(<Memoized />)).toBe(true);
143+
expect(ReactIs.isMemo(<Component />)).toBe(false);
138144
});
139145

140146
it('should identify lazy', () => {
141147
const Component = () => React.createElement('div');
142-
const lazyComponent = React.lazy(() => Component);
143-
expect(ReactIs.typeOf(lazyComponent)).toBe(ReactIs.Lazy);
144-
expect(ReactIs.isLazy(lazyComponent)).toBe(true);
145-
expect(ReactIs.isLazy(Component)).toBe(false);
148+
const LazyComponent = React.lazy(() => Component);
149+
expect(ReactIs.isValidElementType(LazyComponent)).toBe(true);
150+
expect(ReactIs.typeOf(<LazyComponent />)).toBe(ReactIs.Lazy);
151+
expect(ReactIs.isLazy(<LazyComponent />)).toBe(true);
152+
expect(ReactIs.isLazy(<Component />)).toBe(false);
146153
});
147154

148155
it('should identify strict mode', () => {
156+
expect(ReactIs.isValidElementType(React.StrictMode)).toBe(true);
149157
expect(ReactIs.typeOf(<React.StrictMode />)).toBe(ReactIs.StrictMode);
150158
expect(ReactIs.isStrictMode(<React.StrictMode />)).toBe(true);
151159
expect(ReactIs.isStrictMode({type: ReactIs.StrictMode})).toBe(false);
152160
expect(ReactIs.isStrictMode(<div />)).toBe(false);
153161
});
154162

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

163172
it('should identify profile root', () => {
173+
expect(ReactIs.isValidElementType(React.Profiler)).toBe(true);
164174
expect(
165175
ReactIs.typeOf(<React.Profiler id="foo" onRender={jest.fn()} />),
166176
).toBe(ReactIs.Profiler);

packages/react-test-renderer/src/ReactShallowRenderer.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ class ReactShallowRenderer {
542542
);
543543
invariant(
544544
isForwardRef(element) ||
545-
(typeof element.type === 'function' || isMemo(element.type)),
545+
(typeof element.type === 'function' || isMemo(element)),
546546
'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
547547
'components, but the provided element type was `%s`.',
548548
Array.isArray(element.type)
@@ -559,15 +559,15 @@ class ReactShallowRenderer {
559559
this._reset();
560560
}
561561

562-
const elementType = isMemo(element.type) ? element.type.type : element.type;
562+
const elementType = isMemo(element) ? element.type.type : element.type;
563563
const previousElement = this._element;
564564

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

569569
// Inner memo component props aren't currently validated in createElement.
570-
if (isMemo(element.type) && elementType.propTypes) {
570+
if (isMemo(element) && elementType.propTypes) {
571571
currentlyValidatingElement = element;
572572
checkPropTypes(
573573
elementType.propTypes,
@@ -618,7 +618,7 @@ class ReactShallowRenderer {
618618
this._mountClassComponent(elementType, element, this._context);
619619
} else {
620620
let shouldRender = true;
621-
if (isMemo(element.type) && previousElement !== null) {
621+
if (isMemo(element) && previousElement !== null) {
622622
// This is a Memo component that is being re-rendered.
623623
const compare = element.type.compare || shallowEqual;
624624
if (compare(previousElement.props, element.props)) {
@@ -807,7 +807,7 @@ function getDisplayName(element) {
807807
} else if (typeof element.type === 'string') {
808808
return element.type;
809809
} else {
810-
const elementType = isMemo(element.type) ? element.type.type : element.type;
810+
const elementType = isMemo(element) ? element.type.type : element.type;
811811
return elementType.displayName || elementType.name || 'Unknown';
812812
}
813813
}

0 commit comments

Comments
 (0)