mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Add support for React.pure in ReactDOMServer (#13855)
* 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.
This commit is contained in:
1 parent
15b11d23f9
commit
8ecd4bd4f0
2 files changed
+94
-1
No files matched your search
+71
-1
@@ -14,6 +14,11 @@ 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.
|
||||
@@ -21,6 +26,18 @@ function initModules() {
|
||||
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 {
|
||||
@@ -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} />
|
||||
));
|
||||
|
||||
@@ -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']);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
REACT_PROVIDER_TYPE,
|
||||
REACT_CONTEXT_TYPE,
|
||||
REACT_LAZY_TYPE,
|
||||
REACT_PURE_TYPE,
|
||||
} from 'shared/ReactSymbols';
|
||||
|
||||
import {
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user