Skip to content

Commit bb472ec

Browse files
committed
Add support for React.pure in ReactDOMServer
1 parent 21a79a1 commit bb472ec

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

packages/react-dom/src/__tests__/ReactDOMServerIntegrationSpecialTypes-test.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,28 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
1414
let React;
1515
let ReactDOM;
1616
let ReactDOMServer;
17+
let pure;
18+
let yieldedValues;
19+
let yieldValue;
20+
let clearYields;
1721

1822
function initModules() {
1923
// Reset warning cache.
2024
jest.resetModuleRegistry();
2125
React = require('react');
2226
ReactDOM = require('react-dom');
2327
ReactDOMServer = require('react-dom/server');
28+
pure = React.pure;
29+
30+
yieldedValues = [];
31+
yieldValue = value => {
32+
yieldedValues.push(value);
33+
};
34+
clearYields = () => {
35+
const ret = yieldedValues;
36+
yieldedValues = [];
37+
return ret;
38+
};
2439

2540
// Make them available to the helpers.
2641
return {
@@ -65,4 +80,57 @@ describe('ReactDOMServerIntegration', () => {
6580
expect(div.tagName).toBe('DIV');
6681
expect(div.textContent).toBe('Test');
6782
});
83+
84+
describe('pure functional components', () => {
85+
beforeEach(() => {
86+
resetModules();
87+
});
88+
89+
function Text({text}) {
90+
yieldValue(text);
91+
return <span>{text}</span>;
92+
}
93+
94+
function Counter({count}) {
95+
return <Text text={'Count: ' + count} />;
96+
}
97+
98+
itRenders('basic render', async render => {
99+
const PureCounter = pure(Counter);
100+
const domNode = await render(<PureCounter count={0} />);
101+
expect(domNode.textContent).toEqual('Count: 0');
102+
});
103+
104+
itRenders('when a ref is passed', async render => {
105+
const RefCounter = (props, ref) => <Counter count={ref.current} />;
106+
const PureRefCounter = pure(RefCounter);
107+
108+
const ref = React.createRef();
109+
ref.current = 0;
110+
await render(<PureRefCounter ref={ref} />);
111+
112+
expect(clearYields()).toEqual(['Count: 0']);
113+
});
114+
115+
itRenders('with comparator', async render => {
116+
const PureCounter = pure(Counter, (oldProps, newProps) => false);
117+
await render(<PureCounter count={0} />);
118+
expect(clearYields()).toEqual(['Count: 0']);
119+
});
120+
121+
itRenders(
122+
'comparator functions are not invoked on the server',
123+
async render => {
124+
const PureCounter = pure(Counter, (oldProps, newProps) => {
125+
yieldValue(
126+
`Old count: ${oldProps.count}, New count: ${newProps.count}`,
127+
);
128+
return oldProps.count === newProps.count;
129+
});
130+
131+
await render(<PureCounter count={0} />);
132+
expect(clearYields()).toEqual(['Count: 0']);
133+
},
134+
);
135+
});
68136
});

packages/react-dom/src/server/ReactPartialRenderer.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
REACT_PROFILER_TYPE,
3939
REACT_PROVIDER_TYPE,
4040
REACT_CONTEXT_TYPE,
41+
REACT_PURE_TYPE,
4142
} from 'shared/ReactSymbols';
4243

4344
import {
@@ -964,6 +965,25 @@ class ReactDOMServerRenderer {
964965
this.stack.push(frame);
965966
return '';
966967
}
968+
case REACT_PURE_TYPE: {
969+
const element: ReactElement = ((nextChild: any): ReactElement);
970+
const nextChildren = toArray(
971+
elementType.render(element.props, element.ref),
972+
);
973+
const frame: Frame = {
974+
type: null,
975+
domNamespace: parentNamespace,
976+
children: nextChildren,
977+
childIndex: 0,
978+
context: context,
979+
footer: '',
980+
};
981+
if (__DEV__) {
982+
((frame: any): FrameDev).debugElementStack = [];
983+
}
984+
this.stack.push(frame);
985+
return '';
986+
}
967987
case REACT_PROVIDER_TYPE: {
968988
const provider: ReactProvider<any> = (nextChild: any);
969989
const nextProps = provider.props;

0 commit comments

Comments
 (0)