pure -> memo (#13905)
Dan Abramov committed
Oct 20, 2018 at 12:46 UTC
769b1f270e1251d9dbdce0fcbd9e92e502d059b8
16 files changed
+83
-83
packages/react-dom/src/__tests__/ReactDOMServerIntegrationSpecialTypes-test.js
+11
-11
@@ -15,7 +15,7 @@ let React;
15
let ReactDOM;
16
let ReactDOMServer;
17
let forwardRef;
18
-let pure;
18
+let memo;
19
let yieldedValues;
20
let yieldValue;
21
let clearYields;
@@ -27,7 +27,7 @@ function initModules() {
27
ReactDOM = require('react-dom');
28
ReactDOMServer = require('react-dom/server');
29
forwardRef = React.forwardRef;
30
- pure = React.pure;
30
+ memo = React.memo;
31
32
yieldedValues = [];
33
yieldValue = value => {
@@ -83,7 +83,7 @@ describe('ReactDOMServerIntegration', () => {
83
expect(div.textContent).toBe('Test');
84
});
85
86
- describe('pure functional components', () => {
86
+ describe('memoized functional components', () => {
87
beforeEach(() => {
88
resetModules();
89
});
@@ -98,39 +98,39 @@ describe('ReactDOMServerIntegration', () => {
98
}
99
100
itRenders('basic render', async render => {
101
- const PureCounter = pure(Counter);
102
- const domNode = await render(<PureCounter count={0} />);
101
+ const MemoCounter = memo(Counter);
102
+ const domNode = await render(<MemoCounter count={0} />);
103
expect(domNode.textContent).toEqual('Count: 0');
104
});
105
106
itRenders('composition with forwardRef', async render => {
107
const RefCounter = (props, ref) => <Counter count={ref.current} />;
108
- const PureRefCounter = pure(forwardRef(RefCounter));
108
+ const MemoRefCounter = memo(forwardRef(RefCounter));
109
110
const ref = React.createRef();
111
ref.current = 0;
112
- await render(<PureRefCounter ref={ref} />);
112
+ await render(<MemoRefCounter ref={ref} />);
113
114
expect(clearYields()).toEqual(['Count: 0']);
115
});
116
117
itRenders('with comparator', async render => {
118
- const PureCounter = pure(Counter, (oldProps, newProps) => false);
119
- await render(<PureCounter count={0} />);
118
+ const MemoCounter = memo(Counter, (oldProps, newProps) => false);
119
+ await render(<MemoCounter count={0} />);
120
expect(clearYields()).toEqual(['Count: 0']);
121
});
122
123
itRenders(
124
'comparator functions are not invoked on the server',
125
async render => {
126
- const PureCounter = React.pure(Counter, (oldProps, newProps) => {
126
+ const MemoCounter = React.memo(Counter, (oldProps, newProps) => {
127
yieldValue(
128
`Old count: ${oldProps.count}, New count: ${newProps.count}`,
129
);
130
return oldProps.count === newProps.count;
131
});
132
133
- await render(<PureCounter count={0} />);
133
+ await render(<MemoCounter count={0} />);
134
expect(clearYields()).toEqual(['Count: 0']);
135
},
136
);
packages/react-dom/src/server/ReactPartialRenderer.js
+2
-2
@@ -39,7 +39,7 @@ import {
39
REACT_PROVIDER_TYPE,
40
REACT_CONTEXT_TYPE,
41
REACT_LAZY_TYPE,
42
- REACT_PURE_TYPE,
42
+ REACT_MEMO_TYPE,
43
} from 'shared/ReactSymbols';
44
45
import {
@@ -1002,7 +1002,7 @@ class ReactDOMServerRenderer {
1002
this.stack.push(frame);
1003
return '';
1004
}
1005
- case REACT_PURE_TYPE: {
1005
+ case REACT_MEMO_TYPE: {
1006
const element: ReactElement = ((nextChild: any): ReactElement);
1007
let nextChildren = [
1008
React.createElement(
packages/react-reconciler/src/ReactFiber.js
+6
-6
@@ -35,7 +35,7 @@ import {
35
Profiler,
36
SuspenseComponent,
37
FunctionComponent,
38
- PureComponent,
38
+ MemoComponent,
39
LazyComponent,
40
} from 'shared/ReactWorkTags';
41
import getComponentName from 'shared/getComponentName';
@@ -57,7 +57,7 @@ import {
57
REACT_CONTEXT_TYPE,
58
REACT_CONCURRENT_MODE_TYPE,
59
REACT_SUSPENSE_TYPE,
60
- REACT_PURE_TYPE,
60
+ REACT_MEMO_TYPE,
61
REACT_LAZY_TYPE,
62
} from 'shared/ReactSymbols';
63
@@ -315,8 +315,8 @@ export function resolveLazyComponentTag(Component: Function): WorkTag {
315
if ($$typeof === REACT_FORWARD_REF_TYPE) {
316
return ForwardRef;
317
}
318
- if ($$typeof === REACT_PURE_TYPE) {
319
- return PureComponent;
318
+ if ($$typeof === REACT_MEMO_TYPE) {
319
+ return MemoComponent;
320
}
321
}
322
return IndeterminateComponent;
@@ -470,8 +470,8 @@ export function createFiberFromTypeAndProps(
470
case REACT_FORWARD_REF_TYPE:
471
fiberTag = ForwardRef;
472
break getTag;
473
- case REACT_PURE_TYPE:
474
- fiberTag = PureComponent;
473
+ case REACT_MEMO_TYPE:
474
+ fiberTag = MemoComponent;
475
break getTag;
476
case REACT_LAZY_TYPE:
477
fiberTag = LazyComponent;
packages/react-reconciler/src/ReactFiberBeginWork.js
+14
-14
@@ -30,8 +30,8 @@ import {
30
ContextConsumer,
31
Profiler,
32
SuspenseComponent,
33
- PureComponent,
34
- SimplePureComponent,
33
+ MemoComponent,
34
+ SimpleMemoComponent,
35
LazyComponent,
36
} from 'shared/ReactWorkTags';
37
import {
@@ -231,7 +231,7 @@ function updateForwardRef(
231
return workInProgress.child;
232
}
233
234
-function updatePureComponent(
234
+function updateMemoComponent(
235
current: Fiber | null,
236
workInProgress: Fiber,
237
Component: any,
@@ -244,10 +244,10 @@ function updatePureComponent(
244
if (isSimpleFunctionComponent(type) && Component.compare === null) {
245
// If this is a plain function component without default props,
246
// and with only the default shallow comparison, we upgrade it
247
- // to a SimplePureComponent to allow fast path updates.
248
- workInProgress.tag = SimplePureComponent;
247
+ // to a SimpleMemoComponent to allow fast path updates.
248
+ workInProgress.tag = SimpleMemoComponent;
249
workInProgress.type = type;
250
- return updateSimplePureComponent(
250
+ return updateSimpleMemoComponent(
251
current,
252
workInProgress,
253
type,
@@ -299,7 +299,7 @@ function updatePureComponent(
299
return newChild;
300
}
301
302
-function updateSimplePureComponent(
302
+function updateSimpleMemoComponent(
303
current: Fiber | null,
304
workInProgress: Fiber,
305
Component: any,
@@ -814,8 +814,8 @@ function mountLazyComponent(
814
);
815
break;
816
}
817
- case PureComponent: {
818
- child = updatePureComponent(
817
+ case MemoComponent: {
818
+ child = updateMemoComponent(
819
null,
820
workInProgress,
821
Component,
@@ -826,7 +826,7 @@ function mountLazyComponent(
826
break;
827
}
828
default: {
829
- // This message intentionally doesn't metion ForwardRef or PureComponent
829
+ // This message intentionally doesn't metion ForwardRef or MemoComponent
830
// because the fact that it's a separate type of work is an
831
// implementation detail.
832
invariant(
@@ -1612,11 +1612,11 @@ function beginWork(
1612
workInProgress,
1613
renderExpirationTime,
1614
);
1615
- case PureComponent: {
1615
+ case MemoComponent: {
1616
const type = workInProgress.type;
1617
const unresolvedProps = workInProgress.pendingProps;
1618
const resolvedProps = resolveDefaultProps(type.type, unresolvedProps);
1619
- return updatePureComponent(
1619
+ return updateMemoComponent(
1620
current,
1621
workInProgress,
1622
type,
@@ -1625,8 +1625,8 @@ function beginWork(
1625
renderExpirationTime,
1626
);
1627
}
1628
- case SimplePureComponent: {
1629
- return updateSimplePureComponent(
1628
+ case SimpleMemoComponent: {
1629
+ return updateSimpleMemoComponent(
1630
current,
1631
workInProgress,
1632
workInProgress.type,
packages/react-reconciler/src/ReactFiberCompleteWork.js
+4
-4
@@ -34,8 +34,8 @@ import {
34
Mode,
35
Profiler,
36
SuspenseComponent,
37
- PureComponent,
38
- SimplePureComponent,
37
+ MemoComponent,
38
+ SimpleMemoComponent,
39
LazyComponent,
40
} from 'shared/ReactWorkTags';
41
import {Placement, Ref, Update} from 'shared/ReactSideEffectTags';
@@ -540,7 +540,7 @@ function completeWork(
540
break;
541
case LazyComponent:
542
break;
543
- case SimplePureComponent:
543
+ case SimpleMemoComponent:
544
case FunctionComponent:
545
break;
546
case ClassComponent: {
@@ -715,7 +715,7 @@ function completeWork(
715
break;
716
case ContextConsumer:
717
break;
718
- case PureComponent:
718
+ case MemoComponent:
719
break;
720
default:
721
invariant(
packages/react-reconciler/src/__tests__/ReactIncrementalPerf-test.internal.js
+3
-3
@@ -555,13 +555,13 @@ describe('ReactDebugFiberPerf', () => {
555
expect(getFlameChart()).toMatchSnapshot();
556
});
557
558
- it('supports pure', () => {
559
- const PureFoo = React.pure(function Foo() {
558
+ it('supports memo', () => {
559
+ const MemoFoo = React.memo(function Foo() {
560
return <div />;
561
});
562
ReactNoop.render(
563
<Parent>
564
- <PureFoo />
564
+ <MemoFoo />
565
</Parent>,
566
);
567
ReactNoop.flush();
packages/react-reconciler/src/__tests__/ReactMemo-test.internal.js
renamed
+13
-13
@@ -16,7 +16,7 @@ let React;
16
let ReactFeatureFlags;
17
let ReactNoop;
18
19
-describe('pure', () => {
19
+describe('memo', () => {
20
beforeEach(() => {
21
jest.resetModules();
22
ReactFeatureFlags = require('shared/ReactFeatureFlags');
@@ -38,22 +38,22 @@ describe('pure', () => {
38
return {default: result};
39
}
40
41
- // Tests should run against both the lazy and non-lazy versions of `pure`.
41
+ // Tests should run against both the lazy and non-lazy versions of `memo`.
42
// To make the tests work for both versions, we wrap the non-lazy version in
43
// a lazy function component.
44
sharedTests('normal', (...args) => {
45
- const Pure = React.pure(...args);
45
+ const Memo = React.memo(...args);
46
function Indirection(props) {
47
- return <Pure {...props} />;
47
+ return <Memo {...props} />;
48
}
49
return React.lazy(() => fakeImport(Indirection));
50
});
51
sharedTests('lazy', (...args) => {
52
- const Pure = React.pure(...args);
53
- return React.lazy(() => fakeImport(Pure));
52
+ const Memo = React.memo(...args);
53
+ return React.lazy(() => fakeImport(Memo));
54
});
55
56
- function sharedTests(label, pure) {
56
+ function sharedTests(label, memo) {
57
describe(`${label}`, () => {
58
it('bails out on props equality', async () => {
59
const {unstable_Suspense: Suspense} = React;
@@ -61,7 +61,7 @@ describe('pure', () => {
61
function Counter({count}) {
62
return <Text text={count} />;
63
}
64
- Counter = pure(Counter);
64
+ Counter = memo(Counter);
65
66
ReactNoop.render(
67
<Suspense fallback={<Text text="Loading..." />}>
@@ -108,7 +108,7 @@ describe('pure', () => {
108
const count = readContext(CountContext);
109
return <Text text={`${props.label}: ${count}`} />;
110
}
111
- Counter = pure(Counter);
111
+ Counter = memo(Counter);
112
113
class Parent extends React.Component {
114
state = {count: 0};
@@ -147,7 +147,7 @@ describe('pure', () => {
147
function Counter({count}) {
148
return <Text text={count} />;
149
}
150
- Counter = pure(Counter, (oldProps, newProps) => {
150
+ Counter = memo(Counter, (oldProps, newProps) => {
151
ReactNoop.yield(
152
`Old count: ${oldProps.count}, New count: ${newProps.count}`,
153
);
@@ -192,7 +192,7 @@ describe('pure', () => {
192
return <Text text={this.props.count + '' + this.props.suffix} />;
193
}
194
}
195
- const Counter = pure(CounterInner);
195
+ const Counter = memo(CounterInner);
196
197
ReactNoop.render(
198
<Suspense fallback={<Text text="Loading..." />}>
@@ -224,8 +224,8 @@ describe('pure', () => {
224
});
225
226
it('warns if first argument is undefined', () => {
227
- expect(() => pure()).toWarnDev(
228
- 'pure: The first argument must be a component. Instead ' +
227
+ expect(() => memo()).toWarnDev(
228
+ 'memo: The first argument must be a component. Instead ' +
229
'received: undefined',
230
{withoutStack: true},
231
);
packages/react-reconciler/src/__tests__/__snapshots__/ReactIncrementalPerf-test.internal.js.snap
+1
-1
@@ -410,7 +410,7 @@ exports[`ReactDebugFiberPerf supports portals 1`] = `
410
"
411
`;
412
413
-exports[`ReactDebugFiberPerf supports pure 1`] = `
413
+exports[`ReactDebugFiberPerf supports memo 1`] = `
414
"⚛ (Waiting for async callback... will force flush in 5250 ms)
415
416
⚛ (React Tree Reconciliation: Completed Root)
packages/react-test-renderer/src/ReactTestRenderer.js
+5
-5
@@ -27,8 +27,8 @@ import {
27
Mode,
28
ForwardRef,
29
Profiler,
30
- PureComponent,
31
- SimplePureComponent,
30
+ MemoComponent,
31
+ SimpleMemoComponent,
32
} from 'shared/ReactWorkTags';
33
import invariant from 'shared/invariant';
34
import ReactVersion from 'shared/ReactVersion';
@@ -167,7 +167,7 @@ function toTree(node: ?Fiber) {
167
rendered: childrenToTree(node.child),
168
};
169
case FunctionComponent:
170
- case SimplePureComponent:
170
+ case SimpleMemoComponent:
171
return {
172
nodeType: 'component',
173
type: node.type,
@@ -192,7 +192,7 @@ function toTree(node: ?Fiber) {
192
case Mode:
193
case Profiler:
194
case ForwardRef:
195
- case PureComponent:
195
+ case MemoComponent:
196
return childrenToTree(node.child);
197
default:
198
invariant(
@@ -208,7 +208,7 @@ const validWrapperTypes = new Set([
208
ClassComponent,
209
HostComponent,
210
ForwardRef,
211
- PureComponent,
211
+ MemoComponent,
212
// Normally skipped, but used when there's more than one root child.
213
HostRoot,
214
]);
packages/react/src/React.js
+2
-2
@@ -26,7 +26,7 @@ import {
26
import {createContext} from './ReactContext';
27
import {lazy} from './ReactLazy';
28
import forwardRef from './forwardRef';
29
-import pure from './pure';
29
+import memo from './memo';
30
import {
31
createElementWithValidation,
32
createFactoryWithValidation,
@@ -50,7 +50,7 @@ const React = {
50
createContext,
51
forwardRef,
52
lazy,
53
- pure,
53
+ memo,
54
55
Fragment: REACT_FRAGMENT_TYPE,
56
StrictMode: REACT_STRICT_MODE_TYPE,
packages/react/src/__tests__/forwardRef-test.js
+11
-11
@@ -227,7 +227,7 @@ describe('forwardRef', () => {
227
);
228
});
229
230
- it('should not bailout if forwardRef is not wrapped in pure', () => {
230
+ it('should not bailout if forwardRef is not wrapped in memo', () => {
231
const Component = props => <div {...props} />;
232
233
let renderCount = 0;
@@ -248,12 +248,12 @@ describe('forwardRef', () => {
248
expect(renderCount).toBe(2);
249
});
250
251
- it('should bailout if forwardRef is wrapped in pure', () => {
251
+ it('should bailout if forwardRef is wrapped in memo', () => {
252
const Component = props => <div ref={props.forwardedRef} />;
253
254
let renderCount = 0;
255
256
- const RefForwardingComponent = React.pure(
256
+ const RefForwardingComponent = React.memo(
257
React.forwardRef((props, ref) => {
258
renderCount++;
259
return <Component {...props} forwardedRef={ref} />;
@@ -288,12 +288,12 @@ describe('forwardRef', () => {
288
expect(renderCount).toBe(3);
289
});
290
291
- it('should custom pure comparisons to compose', () => {
291
+ it('should custom memo comparisons to compose', () => {
292
const Component = props => <div ref={props.forwardedRef} />;
293
294
let renderCount = 0;
295
296
- const RefForwardingComponent = React.pure(
296
+ const RefForwardingComponent = React.memo(
297
React.forwardRef((props, ref) => {
298
renderCount++;
299
return <Component {...props} forwardedRef={ref} />;
@@ -319,34 +319,34 @@ describe('forwardRef', () => {
319
ReactNoop.flush();
320
expect(renderCount).toBe(2);
321
322
- const ComposedPure = React.pure(
322
+ const ComposedMemo = React.memo(
323
RefForwardingComponent,
324
(o, p) => o.a === p.a && o.c === p.c,
325
);
326
327
- ReactNoop.render(<ComposedPure ref={ref} a="0" b="0" c="0" />);
327
+ ReactNoop.render(<ComposedMemo ref={ref} a="0" b="0" c="0" />);
328
ReactNoop.flush();
329
expect(renderCount).toBe(3);
330
331
// Changing just b no longer updates
332
- ReactNoop.render(<ComposedPure ref={ref} a="0" b="1" c="0" />);
332
+ ReactNoop.render(<ComposedMemo ref={ref} a="0" b="1" c="0" />);
333
ReactNoop.flush();
334
expect(renderCount).toBe(3);
335
336
// Changing just a and c updates
337
- ReactNoop.render(<ComposedPure ref={ref} a="2" b="2" c="2" />);
337
+ ReactNoop.render(<ComposedMemo ref={ref} a="2" b="2" c="2" />);
338
ReactNoop.flush();
339
expect(renderCount).toBe(4);
340
341
// Changing just c does not update
342
- ReactNoop.render(<ComposedPure ref={ref} a="2" b="2" c="3" />);
342
+ ReactNoop.render(<ComposedMemo ref={ref} a="2" b="2" c="3" />);
343
ReactNoop.flush();
344
expect(renderCount).toBe(4);
345
346
// Changing ref still rerenders
347
const differentRef = React.createRef();
348
349
- ReactNoop.render(<ComposedPure ref={differentRef} a="2" b="2" c="3" />);
349
+ ReactNoop.render(<ComposedMemo ref={differentRef} a="2" b="2" c="3" />);
350
ReactNoop.flush();
351
expect(renderCount).toBe(5);
352
packages/react/src/memo.js
renamed
+4
-4
@@ -5,12 +5,12 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
-import {REACT_PURE_TYPE} from 'shared/ReactSymbols';
8
+import {REACT_MEMO_TYPE} from 'shared/ReactSymbols';
9
10
import isValidElementType from 'shared/isValidElementType';
11
import warningWithoutStack from 'shared/warningWithoutStack';
12
13
-export default function pure<Props>(
13
+export default function memo<Props>(
14
type: React$ElementType,
15
compare?: (oldProps: Props, newProps: Props) => boolean,
16
) {
@@ -18,14 +18,14 @@ export default function pure<Props>(
18
if (!isValidElementType(type)) {
19
warningWithoutStack(
20
false,
21
- 'pure: The first argument must be a component. Instead ' +
21
+ 'memo: The first argument must be a component. Instead ' +
22
'received: %s',
23
type === null ? 'null' : typeof type,
24
);
25
}
26
}
27
return {
28
- $$typeof: REACT_PURE_TYPE,
28
+ $$typeof: REACT_MEMO_TYPE,
29
type,
30
compare: compare === undefined ? null : compare,
31
};
packages/shared/ReactSymbols.js
+1
-1
@@ -41,7 +41,7 @@ export const REACT_FORWARD_REF_TYPE = hasSymbol
41
export const REACT_SUSPENSE_TYPE = hasSymbol
42
? Symbol.for('react.suspense')
43
: 0xead1;
44
-export const REACT_PURE_TYPE = hasSymbol ? Symbol.for('react.pure') : 0xead3;
44
+export const REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
45
export const REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4;
46
47
const MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
packages/shared/ReactWorkTags.js
+2
-2
@@ -42,6 +42,6 @@ export const ContextProvider = 10;
42
export const ForwardRef = 11;
43
export const Profiler = 12;
44
export const SuspenseComponent = 13;
45
-export const PureComponent = 14;
46
-export const SimplePureComponent = 15;
45
+export const MemoComponent = 14;
46
+export const SimpleMemoComponent = 15;
47
export const LazyComponent = 16;
packages/shared/getComponentName.js
+2
-2
@@ -16,7 +16,7 @@ import {
16
REACT_FORWARD_REF_TYPE,
17
REACT_FRAGMENT_TYPE,
18
REACT_PORTAL_TYPE,
19
- REACT_PURE_TYPE,
19
+ REACT_MEMO_TYPE,
20
REACT_PROFILER_TYPE,
21
REACT_PROVIDER_TYPE,
22
REACT_STRICT_MODE_TYPE,
@@ -79,7 +79,7 @@ function getComponentName(type: mixed): string | null {
79
return 'Context.Provider';
80
case REACT_FORWARD_REF_TYPE:
81
return getWrappedName(type, type.render, 'ForwardRef');
82
- case REACT_PURE_TYPE:
82
+ case REACT_MEMO_TYPE:
83
return getComponentName(type.type);
84
case REACT_LAZY_TYPE: {
85
const thenable: LazyComponent<mixed> = (type: any);
packages/shared/isValidElementType.js
+2
-2
@@ -16,7 +16,7 @@ import {
16
REACT_PROVIDER_TYPE,
17
REACT_STRICT_MODE_TYPE,
18
REACT_SUSPENSE_TYPE,
19
- REACT_PURE_TYPE,
19
+ REACT_MEMO_TYPE,
20
REACT_LAZY_TYPE,
21
} from 'shared/ReactSymbols';
22
@@ -33,7 +33,7 @@ export default function isValidElementType(type: mixed) {
33
(typeof type === 'object' &&
34
type !== null &&
35
(type.$$typeof === REACT_LAZY_TYPE ||
36
- type.$$typeof === REACT_PURE_TYPE ||
36
+ type.$$typeof === REACT_MEMO_TYPE ||
37
type.$$typeof === REACT_PROVIDER_TYPE ||
38
type.$$typeof === REACT_CONTEXT_TYPE ||
39
type.$$typeof === REACT_FORWARD_REF_TYPE))