React SSR闪烁页面

时间:2019-07-16 12:52:22

标签: javascript reactjs webpack ssr react-loadable

我用React,react-router,@ loadable / component创建了一个项目。

现在,我正在尝试将SSR添加到该项目中。 我用react-router进行服务器端渲染。

然后我添加了@ loadable / component来导入所有页面组件:

import loadable from '@loadable/component';

const routersConfig = [
  {
    path: '/',
    component: loadable(() => import('./Home')),
    exact: true,
  },
  {
    path: '/2',
    component: loadable(() => import('./Home2')),
    exact: true,
  },
];

然后我添加了所有以下代码部分:https://www.smooth-code.com/open-source/loadable-components/docs/server-side-rendering/

现在它可以工作了。 但这可以解决问题:加载时内容闪烁。

我如何理解页面的加载过程:

  1. 浏览器获取由SSR生成的内容(“网络”标签中的第一个查询)
  2. 浏览器呈现内容(具有左边界和上边界)
  3. 浏览器从html下载两个入口点和供应商(app.js,normalizer.js,vendor.js)
  4. 浏览器执行app.js和normalizer.js。左和上边距被删除。
  5. App.js开始下载页面的块-home.js。 此刻内容消失
  6. 下载home.js后,内容再次出现。

我拍摄了一段视频来说明这个过程。 (对于质量,我感到抱歉,stackoverflow禁止文件大小超过2MB)。我正在限制网络速度以想象所有页面的下载过程。

enter image description here

我的问题是为什么内容消失了?如何解决?

我的代码

server.js

const sheetStyledComponents = new ServerStyleSheet();
  const sheetsJssRegistry = createSheetsRegistry();
  const statsFile = path.resolve(process.cwd(), './build-ssr/dist/loadable-stats.json');

  const extractor = new ChunkExtractor({
    statsFile,
    entrypoints: [
      'app',
      'normalize',
    ],
  });


  try {
    const client = ApolloSSRClient();

    const tree = (
      <ApolloProvider client={client}>
        <ApplyTheme sheetsRegistry={sheetsJssRegistry}>
          <StaticRouter location={req.url}>
            <Home />
          </StaticRouter>
        </ApplyTheme>
      </ApolloProvider>
    );

// there is combination of Apollo graphql, jss, styledComponent functions
    const body = await getMarkupFromTree({
      renderFunction: flow(
        sheetStyledComponents.collectStyles.bind(sheetStyledComponents),
        extractor.collectChunks.bind(extractor),
        renderToString
      ),
      tree,
    });

    const scriptTags = extractor.getScriptTags(); 
    // It isn't used yet
    const linkTags = extractor.getLinkTags(); 

    const styleTags = sheetStyledComponents.getStyleTags();

    const html = (await rawHtml)
      .replace(
        '</head>',
        ` 
          ${styleTags}
          <style type="text/css" id='jss-server-side-styles'>
              ${sheetsJssRegistry.toString()}
          </style>
          <script>
            window.__APOLLO_STATE__ = ${JSON.stringify(client.extract())};
          </script>
          ${scriptTags}
          </head>
        `
      )
      .replace('<div id="app"></div>', `<div id="app">${body}</div>`);


    res.send(html);

index.jsx

const SSRApp = (
  <ApolloProvider client={ApolloClient}>
    <ApplyTheme>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </ApplyTheme>
  </ApolloProvider>
);

loadableReady(() => (
  ReactDOM.hydrate(
    SSRApp,
    document.getElementById('app'),
  )
));

2 个答案:

答案 0 :(得分:1)

这是我的错。

该应用的水化版本包含 BrowserRouter->交换机->路由器->主页

SSR版本仅包含 StaticRouter->主页

因此,在渲染SSR版本后,react删除了所有DOM并使用Router创建了一个新的DOM。

答案 1 :(得分:0)

我在server.js中进行了更改。它对我有用

您可能是(server / index.js或server.js或server / app.js..etc)

import Express from 'express';
import Loadable from 'react-loadable';

// from //


  app.listen(3000, () => {
    console.log('app now listening on port', port);
  });


// to //

  import Loadable from 'react-loadable';

  Loadable.preloadAll().then(() => {
     app.listen(port, () => {
     console.log('app now listening on port', port);
   });
  });

进一步了解配置you can see

从服务器渲染正确内容的第一步是确保在渲染时,所有可加载组件均已加载。

为此,可以使用Loadable.preloadAll方法。它返回一个承诺,当所有可加载组件准备就绪时,它将解决。