Skip to content

Commit

Permalink
Add support for React.pure in ReactDOMServer (facebook#13855)
Browse files Browse the repository at this point in the history
* Add support for React.pure in ReactDOMServer

* Unwrap pure wrappers by creating an additional element as a single child

This is very slow but meh. We're rewriting this whole thing anyway.
  • Loading branch information
alexmckenley authored and linjiajian999 committed Oct 22, 2018
1 parent 5783a9b commit 8e89c06
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,30 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
let forwardRef;
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');
forwardRef = React.forwardRef;
pure = React.pure;

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

// Make them available to the helpers.
return {
Expand All @@ -40,7 +57,7 @@ describe('ReactDOMServerIntegration', () => {
const FunctionComponent = ({label, forwardedRef}) => (
<div ref={forwardedRef}>{label}</div>
);
const WrappedFunctionComponent = React.forwardRef((props, ref) => (
const WrappedFunctionComponent = forwardRef((props, ref) => (
<FunctionComponent {...props} forwardedRef={ref} />
));

Expand All @@ -65,4 +82,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('composition with forwardRef', async render => {
const RefCounter = (props, ref) => <Counter count={ref.current} />;
const PureRefCounter = pure(forwardRef(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 = React.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']);
},
);
});
});
23 changes: 23 additions & 0 deletions packages/react-dom/src/server/ReactPartialRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
REACT_PROVIDER_TYPE,
REACT_CONTEXT_TYPE,
REACT_LAZY_TYPE,
REACT_PURE_TYPE,
} from 'shared/ReactSymbols';

import {
Expand Down Expand Up @@ -1001,6 +1002,28 @@ class ReactDOMServerRenderer {
this.stack.push(frame);
return '';
}
case REACT_PURE_TYPE: {
const element: ReactElement = ((nextChild: any): ReactElement);
let nextChildren = [
React.createElement(
elementType.type,
Object.assign({ref: element.ref}, element.props),
),
];
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 8e89c06

Please sign in to comment.