SSR结合React-Router

作者: binyellow | 来源:发表于2019-04-21 17:28 被阅读21次

    服务端根据请求url来返回对应的页面

    1. StaticRouter支持服务端渲染的路由,它的位置一直不变,只是根据请求的url来定位location并渲染对一个的组件
    2.  <StaticRouter context={ context } location={ req.url }>
         <Layout />
       </StaticRouter>
      

    服务端返回格式好的html后

    1. 加载客户端的代码,加载好事件绑定后
    2. 客户端接管路由跳转和ajax请求
    3.  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/');
      });
    });
    

    按需加载实现原理

    1. 在webpack中可以通过require.ensureimport()来实现
    2. 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}/>
          )
        }
      }
    

    相关文章

      网友评论

        本文标题:SSR结合React-Router

        本文链接:https://www.haomeiwen.com/subject/caejgqtx.html