React-Composite-Pages
React-Composite-Pages composes universal components into pages using any combination of flux implementations.
Scenarios
A common pattern with React is to separate Presentational Components from Container Components. Presentational Components should be dumb--operating only with props and callbacks, whereas Container Components are smart--connected to your Flux implementation, and in charge of managing state.
There are many scenarios for composing multiple React Container Components together onto a single page; including:
- Interactive navigation components and other common controls
- Dashboard screens that comprise many independent sections
- Composition of components using different flux implementations (or versions)
React-Composite-Pages renders multiple Container Components on a page, regardless of flux implementation, yet still achieve universal rendering.
Running the Examples
To run the examples, you first need to build the react-composite-pages package, and then start up the examples server. This has all been wrapped up into a single command at the root of the repository
npm run examples
Usage
On the server, you will wrap your Container Components in Server Pages that allow for simple async consumption, rendering the Container Components into Page Templates.
On the client, you can easily access the server's render state to initialize client-side flux loops and rendering.
Hello World Example
Here's a bare-bones Hello World example (that does not utilize a flux implementation).
Presentational Component: pages/hello/Hello.jsx
import React from 'react';;
Server Page: pages/hello/index.js
import React from 'react';import url from 'url';import Hello from './Hello';import template from '../../templates/basic';import Container from 'react-composite-pages';req res callback// This could be an async data fetching operationconst to = "World" = urlquery;// This could be the creation of a flux/redux storeconst state = to ;// Load the Template Component using this same approach;}
Page Template: templates/basic.js
import React from 'react';import renderTemplate PageClients PageState from 'react-composite-pages';req res callback// We could perform async operations for loading the template;
Client Entry Point: pages/hello/client.js
This is the client-side bundle entry point for the 'hello' page.
import React from 'react';import ReactDOM from 'react-dom';import Hello from './Hello';import getContainerState from 'react-composite-pages/client';const state = ;const container = document;ReactDOM;
Express Server: server.js
import express from 'express';import url from 'url';import React from 'react';import ReactDOMServer from 'react-dom/server';import routes from './routes';import match from 'react-router';const app = ;app;app;app;
Rendered HTML
The server is using ReactDOMServer.renderToStaticMarkup()
to render the <Page />
that was loaded. This allows the <html>
tag and other elements from the page template to be rendered as static HTML rather than with react attributes.
However, if we examine the output for this page, we'll see that react attributes are applied to each element that was within a <Container>
.
Hello WorldHello WorldIt's nice to see you again!
This happens because the Container
renders its own children using ReactDOMServer.renderToString()
and wraps that React-enabled markup in a <div>
. In the example above, we see <div id="hello-container">
that corresponds to the <Container>
.
This approach ensures that each Container Component can perform client-side rendering cleanly, gaining a flicker-free initial render, and no warnings about rendering React components into elements that themselves were rendered from React.
Advanced Topics
There's also a post that walks through the inspiration behind React-Composite-Pages:
A pattern for server-side async data loading with React components
Summary
The patterns set forth by React-Composite-Pages are very straight-forward:
- Server Pages export functions that accept the request, response, and a callback (similar to Express middleware)
- The callback will receive a React component
- Functions can also be specified to represent the Container Component's external API
- The React components can use Page Templates with template sections
- Template sections are Components wrapped in a
Container
- The
Container
receives state and client script to be used for client-side rendering
- Template sections are Components wrapped in a
- The server simply loads a page and renders its React component
- The server code does not need to be aware of which page template to render; the page wraps itself in the appropriate template
- The server code remains independent from any flux implementation in use on the page
- Client-side entry points load the state and initialize client-side rendering
With this approach, we can easily compose Container Components together into page templates and support universal rendering of any Container Component, regardless of its flux implementation--even mixing flux implementations together cleanly.