React SSR 闪烁页面

React SSR blinks page

我用 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后,内容再次出现。

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

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

我的代码

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'),
  )
));

是我的错。

水合版app包含BrowserRouter -> Switch -> Router -> HomePage

并且SSR版本只包含StaticRouter -> HomePage

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

我在 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 方法。它 returns 一个将在所有可加载组件准备就绪时解决的承诺。