ISOMORPHIC APPS:
(JUST) THE GOOD PARTS
@marianodvazquez
github.com/nanovazquez
Isomorphic JavaScript apps are that run the same code in the client and the server
isomorphic, universal, server-side rendering, client-side rendering
You heard it here first — within a few years, it will be rare to see an advanced web app that isn’t running some JavaScript on the server.
Isomorphic JavaScript: The Future of Web Apps (2013)
Is a term used to emphasize the fact that a particular piece of JavaScript code is able to run in multiple environments
Using Universal JavaScript means the rendering logic is simply passed down to the client.
Making Netflix.com faster (2015)
Isomorphic also is the functional aspect of seamlessly switching between client and server side rendering
without losing state
To send the data down to the client, we need to:
create a fresh, new Redux store instance on every request;
optionally dispatch some actions;
pull the state out of store;
and then pass the state along to the client.
On the client side, a new Redux store will be created and initialized with the state provided from the server.
Redux's only job on the server side is to provide the initial state of our app.
import path from 'path'
import Express from 'express'
import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import counterApp from './reducers'
import App from './containers/App'
const app = Express()
const port = 3000
// This is fired every time the server side receives a request
app.use(handleRender)
// We are going to fill these out in the sections to follow
function handleRender(req, res) { /* ... */ }
function renderFullPage(html, preloadedState) { /* ... */ }
app.listen(port)
import { renderToString } from 'react-dom/server'
function handleRender(req, res) {
// Create a new Redux store instance
const store = createStore(counterApp)
// Render the component to a string
const html = renderToString(
<Provider store={store}>
<App />
</Provider>
)
// Grab the initial state from our Redux store
const preloadedState = store.getState()
// Send the rendered page back to the client
res.send(renderFullPage(html, preloadedState))
}
function renderFullPage(html, preloadedState) {
return `
<!doctype html>
<html>
<head>
<title>Redux Universal Example</title>
</head>
<body>
<div id="root">${html}</div>
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)}
</script>
<script src="/static/bundle.js"></script>
</body>
</html>
`
}
import React from 'react'
import { render } from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import App from './containers/App'
import counterApp from './reducers'
// Grab the state from a global injected into server-generated HTML
const preloadedState = window.__PRELOADED_STATE__
// Create Redux store with initial state
const store = createStore(counterApp, preloadedState)
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
Since we have the same initial state for our (client) Redux store the result will be the same real DOM.
more info here
A minimalistic framework for universal server-rendered React applications