server
服务端渲染主要为客户端提供一个初始state
通过import ReactDOM from 'react-dom/server';
获取ReactDOM对象
用来将组件渲染为HTML
字符串
一下是一个用Express搭建的服务端
import 'babel-core/polyfill';
import path from 'path';
import express from 'express';
import React from 'react';
import ReactDOM from 'react-dom/server';
import Router from './routes';
import Html from './components/Html';
import assets from './assets.json';
import createStore from './stores/create';
import {Provider} from 'react-redux';
const debug = require('debug')('hedge:server');
const DevTools = require('./components/DevTools/DevTools');
const server = global.server = express();
const port = process.env.PORT || 5000;
server.set('port', port);
//
// Register Node.js middleware
// -----------------------------------------------------------------------------
server.use(express.static(path.join(__dirname, 'public')));
server.get('*', async (req, res, next) => {
try {
let statusCode = 200;
const data = { title: '', description: '', css: '', body: '', entry: assets.app.js, bodyClassName: '' };
const css = [];
const context = {
insertCss: styles => css.push(styles._getCss()),
onSetTitle: value => data.title = value,
onSetMeta: (key, value) => data[key] = value,
onPageNotFound: () => statusCode = 404,
onSetBodyClassName: className => data.bodyClassName = className
};
let currentMenu = { currentMenu: { currentMenu: req.path.substr(1) } };
const store = createStore(currentMenu);
await Router.dispatch({ path: req.path, context }, (state, component) => {
data.body = ReactDOM.renderToString(
<Provider store={store} key="provider">
<div>
{component}
<DevTools />
</div>
</Provider>
);
data.css = css.join('');
});
debug('do server side render [%s]', req.path);
const html = ReactDOM.renderToStaticMarkup(<Html {...data} store={store}/>);
res.status(statusCode).send('<!doctype html>\n' + html);
} catch (err) {
next(err);
}
});
// 运行
server.listen(port, () => {
console.log(`The server is running at http://localhost:${port}/`);
});
通过以上代码可以看到通过ReactDOM.renderToStaticMarkup
最终返回的字符串.
还有一点服务器的state
要保存到window.__INITIAL_STATE__
如:
<body className={this.props.bodyClassName}>
<div id="app" dangerouslySetInnerHTML={{ __html: this.props.body }} />
<script dangerouslySetInnerHTML={{ __html: `window.__INITIAL_STATE__=${serialize(this.props.store.getState())};` }} charSet="UTF-8"/>
<script src={this.props.entry}></script>
<script dangerouslySetInnerHTML={this.trackingCode()} />
</body>
客户端
客户端通过window.__INITIAL_STATE__
来装载服务端返回的初始state
示意代码
const store = createStore(window.__INITIAL_STATE__);
function render(state) {
Router.dispatch(state, (newState, component) => {
ReactDOM.render(
<Provider store={store} key="provider">
<div>
{component}
<DevTools />
</div>
</Provider>,
appContainer
);
});
}