[change] Configure hydration using AppRegistry.runApplication()

Client-side hydration of server-rendered HTML now requires that `hydrate` is explicitly set in the `appParams` passed to `AppRegistry.runApplication()`.

Fix #1374
This commit is contained in:
Nicolas Gallagher
2019-11-12 16:54:51 -08:00
parent e4ed0fd3c8
commit afb8d3b7fb
4 changed files with 31 additions and 18 deletions

View File

@@ -76,15 +76,17 @@ AppRegistry.registerRunnable('MyApp', (appParams) => { ... });
### runApplication(appKey, appParams)
Runs the application that was registered under `appKey`. The `appParameters` must
include the `rootTag` into which the application is rendered, and optionally any
`initialProps` or render callback.
Runs the application that was registered under `appKey`. The `appParameters`
must include the `rootTag` into which the application is rendered, and
optionally any `initialProps` or render callback. If the client should hydrate
server-rendered HTML, set `hydrate` to `true`.
```js
AppRegistry.runApplication('MyApp', {
callback: () => { console.log('React rendering has finished') },
hydrate: true,
initialProps: {},
rootTag: document.getElementById('react-root'),
callback: () => { console.log('React rendering has finished') }
})
```

View File

@@ -73,19 +73,23 @@ describe('AppRegistry', () => {
});
describe('runApplication', () => {
test('callback after render', () => {
// setup
const rootTag = document.createElement('div');
let rootTag;
beforeEach(() => {
rootTag = document.createElement('div');
rootTag.id = 'react-root';
document.body.appendChild(rootTag);
});
afterEach(() => {
document.body.removeChild(rootTag);
});
test('callback after render', () => {
const callback = jest.fn();
AppRegistry.registerComponent('App', () => NoopComponent);
AppRegistry.runApplication('App', { initialProps: {}, rootTag, callback });
expect(callback).toHaveBeenCalledTimes(1);
// cleanup
document.body.removeChild(rootTag);
});
});
});

View File

@@ -63,10 +63,13 @@ export default class AppRegistry {
run: appParameters =>
renderApplication(
componentProviderInstrumentationHook(componentProvider),
appParameters.initialProps || emptyObject,
appParameters.rootTag,
wrapperComponentProvider && wrapperComponentProvider(appParameters),
appParameters.callback
appParameters.callback,
{
hydrate: appParameters.hydrate || false,
initialProps: appParameters.initialProps || emptyObject,
rootTag: appParameters.rootTag
}
)
};
return appKey;

View File

@@ -15,15 +15,19 @@ import render from '../render';
import styleResolver from '../StyleSheet/styleResolver';
import React, { type ComponentType } from 'react';
const renderFn = process.env.NODE_ENV !== 'production' ? render : hydrate;
export default function renderApplication<Props: Object>(
RootComponent: ComponentType<Props>,
initialProps: Props,
rootTag: any,
WrapperComponent?: ?ComponentType<*>,
callback?: () => void
callback?: () => void,
options: {
hydrate: boolean,
initialProps: Props,
rootTag: any
}
) {
const { hydrate: shouldHydrate, initialProps, rootTag } = options;
const renderFn = shouldHydrate ? hydrate : render;
invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);
renderFn(