From afb8d3b7fbe03feb7a79ca069c1c246787a51060 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Tue, 12 Nov 2019 16:54:51 -0800 Subject: [PATCH] [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 --- .../src/apis/AppRegistry/AppRegistry.stories.mdx | 10 ++++++---- .../exports/AppRegistry/__tests__/index-test.js | 16 ++++++++++------ .../src/exports/AppRegistry/index.js | 9 ++++++--- .../src/exports/AppRegistry/renderApplication.js | 14 +++++++++----- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/packages/docs/src/apis/AppRegistry/AppRegistry.stories.mdx b/packages/docs/src/apis/AppRegistry/AppRegistry.stories.mdx index c7cb7993..0f3c0f8d 100644 --- a/packages/docs/src/apis/AppRegistry/AppRegistry.stories.mdx +++ b/packages/docs/src/apis/AppRegistry/AppRegistry.stories.mdx @@ -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') } }) ``` diff --git a/packages/react-native-web/src/exports/AppRegistry/__tests__/index-test.js b/packages/react-native-web/src/exports/AppRegistry/__tests__/index-test.js index 2541f029..40312eeb 100644 --- a/packages/react-native-web/src/exports/AppRegistry/__tests__/index-test.js +++ b/packages/react-native-web/src/exports/AppRegistry/__tests__/index-test.js @@ -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); }); }); }); diff --git a/packages/react-native-web/src/exports/AppRegistry/index.js b/packages/react-native-web/src/exports/AppRegistry/index.js index f085cc56..ce8c1f5f 100644 --- a/packages/react-native-web/src/exports/AppRegistry/index.js +++ b/packages/react-native-web/src/exports/AppRegistry/index.js @@ -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; diff --git a/packages/react-native-web/src/exports/AppRegistry/renderApplication.js b/packages/react-native-web/src/exports/AppRegistry/renderApplication.js index d8d6f135..ecc09783 100644 --- a/packages/react-native-web/src/exports/AppRegistry/renderApplication.js +++ b/packages/react-native-web/src/exports/AppRegistry/renderApplication.js @@ -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( RootComponent: ComponentType, - 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(