Fix react-is memo and lazy type checks (#17278)
Brian Vaughn committed
Nov 5, 2019 at 10:37 UTC
053cf0fedc91a1507080afe43d3be354ec346e9e
3 files changed
+25
-15
packages/react-is/src/ReactIs.js
+2
-2
@@ -48,14 +48,14 @@ export function typeOf(object: any) {
48
switch ($$typeofType) {
49
case REACT_CONTEXT_TYPE:
50
case REACT_FORWARD_REF_TYPE:
51
+ case REACT_LAZY_TYPE:
52
+ case REACT_MEMO_TYPE:
53
case REACT_PROVIDER_TYPE:
54
return $$typeofType;
55
default:
56
return $$typeof;
57
}
58
}
57
- case REACT_LAZY_TYPE:
58
- case REACT_MEMO_TYPE:
59
case REACT_PORTAL_TYPE:
60
return $$typeof;
61
}
packages/react-is/src/__tests__/ReactIs-test.js
+18
-8
@@ -71,6 +71,7 @@ describe('ReactIs', () => {
71
72
it('should identify context consumers', () => {
73
const Context = React.createContext(false);
74
+ expect(ReactIs.isValidElementType(Context.Consumer)).toBe(true);
75
expect(ReactIs.typeOf(<Context.Consumer />)).toBe(ReactIs.ContextConsumer);
76
expect(ReactIs.isContextConsumer(<Context.Consumer />)).toBe(true);
77
expect(ReactIs.isContextConsumer(<Context.Provider />)).toBe(false);
@@ -79,6 +80,7 @@ describe('ReactIs', () => {
80
81
it('should identify context providers', () => {
82
const Context = React.createContext(false);
83
+ expect(ReactIs.isValidElementType(Context.Provider)).toBe(true);
84
expect(ReactIs.typeOf(<Context.Provider />)).toBe(ReactIs.ContextProvider);
85
expect(ReactIs.isContextProvider(<Context.Provider />)).toBe(true);
86
expect(ReactIs.isContextProvider(<Context.Consumer />)).toBe(false);
@@ -106,6 +108,7 @@ describe('ReactIs', () => {
108
109
it('should identify ref forwarding component', () => {
110
const RefForwardingComponent = React.forwardRef((props, ref) => null);
111
+ expect(ReactIs.isValidElementType(RefForwardingComponent)).toBe(true);
112
expect(ReactIs.typeOf(<RefForwardingComponent />)).toBe(ReactIs.ForwardRef);
113
expect(ReactIs.isForwardRef(<RefForwardingComponent />)).toBe(true);
114
expect(ReactIs.isForwardRef({type: ReactIs.StrictMode})).toBe(false);
@@ -113,6 +116,7 @@ describe('ReactIs', () => {
116
});
117
118
it('should identify fragments', () => {
119
+ expect(ReactIs.isValidElementType(React.Fragment)).toBe(true);
120
expect(ReactIs.typeOf(<React.Fragment />)).toBe(ReactIs.Fragment);
121
expect(ReactIs.isFragment(<React.Fragment />)).toBe(true);
122
expect(ReactIs.isFragment({type: ReactIs.Fragment})).toBe(false);
@@ -124,6 +128,7 @@ describe('ReactIs', () => {
128
it('should identify portals', () => {
129
const div = document.createElement('div');
130
const portal = ReactDOM.createPortal(<div />, div);
131
+ expect(ReactIs.isValidElementType(portal)).toBe(false);
132
expect(ReactIs.typeOf(portal)).toBe(ReactIs.Portal);
133
expect(ReactIs.isPortal(portal)).toBe(true);
134
expect(ReactIs.isPortal(div)).toBe(false);
@@ -131,21 +136,24 @@ describe('ReactIs', () => {
136
137
it('should identify memo', () => {
138
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);
144
});
145
146
it('should identify lazy', () => {
147
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);
153
});
154
155
it('should identify strict mode', () => {
156
+ expect(ReactIs.isValidElementType(React.StrictMode)).toBe(true);
157
expect(ReactIs.typeOf(<React.StrictMode />)).toBe(ReactIs.StrictMode);
158
expect(ReactIs.isStrictMode(<React.StrictMode />)).toBe(true);
159
expect(ReactIs.isStrictMode({type: ReactIs.StrictMode})).toBe(false);
@@ -153,6 +161,7 @@ describe('ReactIs', () => {
161
});
162
163
it('should identify suspense', () => {
164
+ expect(ReactIs.isValidElementType(React.Suspense)).toBe(true);
165
expect(ReactIs.typeOf(<React.Suspense />)).toBe(ReactIs.Suspense);
166
expect(ReactIs.isSuspense(<React.Suspense />)).toBe(true);
167
expect(ReactIs.isSuspense({type: ReactIs.Suspense})).toBe(false);
@@ -161,6 +170,7 @@ describe('ReactIs', () => {
170
});
171
172
it('should identify profile root', () => {
173
+ expect(ReactIs.isValidElementType(React.Profiler)).toBe(true);
174
expect(
175
ReactIs.typeOf(<React.Profiler id="foo" onRender={jest.fn()} />),
176
).toBe(ReactIs.Profiler);
packages/react-test-renderer/src/ReactShallowRenderer.js
+5
-5
@@ -542,7 +542,7 @@ class ReactShallowRenderer {
542
);
543
invariant(
544
isForwardRef(element) ||
545
- (typeof element.type === 'function' || isMemo(element.type)),
545
+ (typeof element.type === 'function' || isMemo(element)),
546
'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
547
'components, but the provided element type was `%s`.',
548
Array.isArray(element.type)
@@ -559,7 +559,7 @@ class ReactShallowRenderer {
559
this._reset();
560
}
561
562
- const elementType = isMemo(element.type) ? element.type.type : element.type;
562
+ const elementType = isMemo(element) ? element.type.type : element.type;
563
const previousElement = this._element;
564
565
this._rendering = true;
@@ -567,7 +567,7 @@ class ReactShallowRenderer {
567
this._context = getMaskedContext(elementType.contextTypes, context);
568
569
// Inner memo component props aren't currently validated in createElement.
570
- if (isMemo(element.type) && elementType.propTypes) {
570
+ if (isMemo(element) && elementType.propTypes) {
571
currentlyValidatingElement = element;
572
checkPropTypes(
573
elementType.propTypes,
@@ -618,7 +618,7 @@ class ReactShallowRenderer {
618
this._mountClassComponent(elementType, element, this._context);
619
} else {
620
let shouldRender = true;
621
- if (isMemo(element.type) && previousElement !== null) {
621
+ if (isMemo(element) && previousElement !== null) {
622
// This is a Memo component that is being re-rendered.
623
const compare = element.type.compare || shallowEqual;
624
if (compare(previousElement.props, element.props)) {
@@ -807,7 +807,7 @@ function getDisplayName(element) {
807
} else if (typeof element.type === 'string') {
808
return element.type;
809
} else {
810
- const elementType = isMemo(element.type) ? element.type.type : element.type;
810
+ const elementType = isMemo(element) ? element.type.type : element.type;
811
return elementType.displayName || elementType.name || 'Unknown';
812
}
813
}