Skip to content

Commit

Permalink
Add support for React.pure in ReactDOMServer
Browse files Browse the repository at this point in the history
  • Loading branch information
alexmckenley committed Oct 16, 2018
1 parent 21a79a1 commit bb472ec
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,28 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
let pure;
let yieldedValues;
let yieldValue;
let clearYields;

function initModules() {
// Reset warning cache.
jest.resetModuleRegistry();
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
pure = React.pure;

yieldedValues = [];
yieldValue = value => {
yieldedValues.push(value);
};
clearYields = () => {
const ret = yieldedValues;
yieldedValues = [];
return ret;
};

// Make them available to the helpers.
return {
Expand Down Expand Up @@ -65,4 +80,57 @@ describe('ReactDOMServerIntegration', () => {
expect(div.tagName).toBe('DIV');
expect(div.textContent).toBe('Test');
});

describe('pure functional components', () => {
beforeEach(() => {
resetModules();
});

function Text({text}) {
yieldValue(text);
return <span>{text}</span>;
}

function Counter({count}) {
return <Text text={'Count: ' + count} />;
}

itRenders('basic render', async render => {
const PureCounter = pure(Counter);
const domNode = await render(<PureCounter count={0} />);
expect(domNode.textContent).toEqual('Count: 0');
});

itRenders('when a ref is passed', async render => {
const RefCounter = (props, ref) => <Counter count={ref.current} />;
const PureRefCounter = pure(RefCounter);

const ref = React.createRef();
ref.current = 0;
await render(<PureRefCounter ref={ref} />);

expect(clearYields()).toEqual(['Count: 0']);
});

itRenders('with comparator', async render => {
const PureCounter = pure(Counter, (oldProps, newProps) => false);
await render(<PureCounter count={0} />);
expect(clearYields()).toEqual(['Count: 0']);
});

itRenders(
'comparator functions are not invoked on the server',
async render => {
const PureCounter = pure(Counter, (oldProps, newProps) => {
yieldValue(
`Old count: ${oldProps.count}, New count: ${newProps.count}`,
);
return oldProps.count === newProps.count;
});

await render(<PureCounter count={0} />);
expect(clearYields()).toEqual(['Count: 0']);
},
);
});
});
20 changes: 20 additions & 0 deletions packages/react-dom/src/server/ReactPartialRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
REACT_PROFILER_TYPE,
REACT_PROVIDER_TYPE,
REACT_CONTEXT_TYPE,
REACT_PURE_TYPE,
} from 'shared/ReactSymbols';

import {
Expand Down Expand Up @@ -964,6 +965,25 @@ class ReactDOMServerRenderer {
this.stack.push(frame);
return '';
}
case REACT_PURE_TYPE: {
const element: ReactElement = ((nextChild: any): ReactElement);
const nextChildren = toArray(
elementType.render(element.props, element.ref),
);
const frame: Frame = {
type: null,
domNamespace: parentNamespace,
children: nextChildren,
childIndex: 0,
context: context,
footer: '',
};
if (__DEV__) {
((frame: any): FrameDev).debugElementStack = [];
}
this.stack.push(frame);
return '';
}
case REACT_PROVIDER_TYPE: {
const provider: ReactProvider<any> = (nextChild: any);
const nextProps = provider.props;
Expand Down

0 comments on commit bb472ec

Please sign in to comment.