服务端根据请求url来返回对应的页面
-
StaticRouter
支持服务端渲染的路由,它的位置一直不变,只是根据请求的url来定位location并渲染对一个的组件
<StaticRouter context={ context } location={ req.url }>
<Layout />
</StaticRouter>
服务端返回格式好的html后
- 加载客户端的代码,加载好事件绑定后
- 客户端接管路由跳转和ajax请求
const jsx = (
<Router>
<Layout />
</Router>
);
ReactDOM.hydrate( jsx, app );
配合react-loadable
实现代码分割和懒加载
公共路由文件
const Home = Loadable({
loader: ()=> import(/* webpackChunkName: 'Home' */'./Home'),
loading,
});
const Hello = Loadable({
loader: ()=> import(/* webpackChunkName: 'Hello' */'./Hello'),
loading,
});
export default class Layout extends React.Component {
constructor() {
super();
this.state = {
title: "Welcome to React SSR!"
};
}
render() {
return (
<div>
<h1>{this.state.title}</h1>
<div>
<Link to="/">Home</Link>
<Link to="/hello">Hello</Link>
</div>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/hello" exact component={Hello} />
</Switch>
</div>
);
}
}
客户端
const jsx = (
<Provider store={store}>
<Router>
<Layout />
</Router>
</Provider>
);
const app = document.getElementById( "app" );
Loadable.preloadReady().then(() => { // 懒加载依赖准备好了,然后去渲染并为dom元素添加事件
ReactDOM.hydrate( jsx, app );
});
服务端
const jsx = (
<Provider store={store}>
<Loadable.Capture report={moduleName => modules.push(moduleName)}>
<StaticRouter context={ context } location={ req.url }>
<Layout />
</StaticRouter>
</Loadable.Capture>
</Provider>
);
const reactDom = renderToStaticMarkup( jsx ); // 不会创建额外的Dom属性
let bundles = getBundles(stats, modules); // 依赖的bundle
const state = store.getState();
htmlTemplate( reactDom, bundles, state )
Loadable.preloadAll().then(() => {
app.listen(3000, () => {
console.log('Running on http://localhost:3000/');
});
});
按需加载实现原理
- 在webpack中可以通过
require.ensure
和import()
来实现
-
react-lodable
高阶组件实现原理
Lodable({
loader: ()=> import(/* webpackChunkName: 'Hello' */'./Hello'),
loading,
})
class Lodable {
componentWillMount() {
this.cancelUpdate = false;
const { loader } = this.props;
loader.then(Com=> {
this.Com = Com;
if(!this.cancelUpdate) {
thi.forceUpdate(); // 初次懒加载完后重新渲染
}
})
}
componentWillUnmount() {
this.cancelUpdate = true;
}
render() {
const { comProps } = this.props;
return this.Com ? (
<this.Com.default {...comProps} />
) : (
<this.Com {...comProps}/>
)
}
}
网友评论