From 5c264702143c609f1150b25608380016938548ac Mon Sep 17 00:00:00 2001 From: Bo Borgerson Date: Mon, 28 Aug 2017 15:29:31 -0700 Subject: [PATCH] Add support for out-of-order render client side React Server assumes that it can render in-order client side since the data required to render each element will necessarily have arrived by the time it is reached. In order to support moving the JS for non-critical above-the-fold components into a secondary bundle, though, we would need support for out-of-order rendering in the browser. --- .../react-server-test-pages/entrypoints.js | 4 +++ .../pages/root/order.js | 35 +++++++++++++++++++ .../react-server/core/ClientController.js | 13 +++---- 3 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 packages/react-server-test-pages/pages/root/order.js diff --git a/packages/react-server-test-pages/entrypoints.js b/packages/react-server-test-pages/entrypoints.js index f890acf4b..46bae69e9 100644 --- a/packages/react-server-test-pages/entrypoints.js +++ b/packages/react-server-test-pages/entrypoints.js @@ -17,6 +17,10 @@ module.exports = { entry: "/root/when", description: "", }, + RootOrder: { + entry: "/root/order", + description: "Out of order render", + }, RootProvider: { entry: "/root/rootProvider", description: "", diff --git a/packages/react-server-test-pages/pages/root/order.js b/packages/react-server-test-pages/pages/root/order.js new file mode 100644 index 000000000..8be7bdba8 --- /dev/null +++ b/packages/react-server-test-pages/pages/root/order.js @@ -0,0 +1,35 @@ +import {Component} from "react"; +import {RootElement} from "react-server"; +import Q from "q"; + +class TurnGreen extends Component { + componentDidMount() { + this.setState({color: "green"}); + } + render() { + const {color} = this.state || {}; + return
{this.props.children}
; + } +} + +export default class RootOrderPage { + handleRoute(next) { + this.first = this.second = Q(); + + if (typeof window !== "undefined") { + this.first = Q.delay(1000); + } + + return next(); + } + getElements() { + return [ + + This should turn green second + , + + This should turn green first + , + ] + } +} diff --git a/packages/react-server/core/ClientController.js b/packages/react-server/core/ClientController.js index 3405a1834..f4b32fe9d 100644 --- a/packages/react-server/core/ClientController.js +++ b/packages/react-server/core/ClientController.js @@ -604,12 +604,8 @@ class ClientController extends EventEmitter { // As elements become ready, prime them to render as soon as // their mount point is available. // - // Always render in order to proritize content higher in the - // page. - // - elementPromisesOr.reduce((chain, promise, index) => chain - .then(() => promise - .then(element => rootNodePromises[index] + Q.all(elementPromisesOr.map((promise, index) => promise.then( + element => rootNodePromises[index] .then(root => renderElement(element, root, index)) .catch(e => { // The only case where this should evaluate to false is @@ -619,9 +615,8 @@ class ClientController extends EventEmitter { : 'element'; logger.error(`Error with element ${componentType}'s lifecycle methods at index ${index}`, e); }) - ).catch(e => logger.error(`Error with element promise ${index}`, e)) - ), - Q()).then(retval.resolve); + ).catch(e => logger.error(`Error with element promise ${index}`, e)) + )).then(retval.resolve); // Look out for a failsafe timeout from the server on our // first render.