【问题标题】:React SSR blinks pageReact SSR 闪烁页面
【发布时间】:2019-07-16 12:52:22
【问题描述】:

我用 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 的文件)。我正在限制网络速度以想象所有页面的下载过程。

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

我的代码

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

【问题讨论】:

  • 我们能看到你的 组件以及你使用 ReactDOM 的代码吗?我认为这可能会有所帮助。
  • 据我所知,您的 js 代码获取了 &lt;div id="app"&gt; 中的所有内容并从头开始渲染。从理论上讲,您的 js 不应该这样做,它应该连接到 &lt;div id="app"&gt; 中的现有组件
  • 在阅读了 react-router 的 github repo 上的文档之后,我们真的需要看看你的 Router 是在哪里定义的,以及它是如何定义的。
  • 我相信您的整个网页都在闪烁,因为整个页面都包含在 中,当您导航到另一个页面时,它会更改内容。如果您希望标题不闪烁,则需要将标题移到 组件之外。试试看,让我知道结果。我对你的设置很感兴趣。
  • @JoshuaBlevins 我发现了错误。它只是试图渲染 SSR 而不是 。你可以在我的代码中看到它。

标签: javascript reactjs webpack server-side-rendering react-loadable


【解决方案1】:

这是我的错。

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

而 SSR 版本只包含 StaticRouter -> HomePage

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

【讨论】:

  • 我也真的需要关于眨眼的帮助。我没有做这样的事情。但它仍然闪烁。
  • @Oleg 我仍然很困惑。你在客户端为location 定义了什么?
【解决方案2】:

我在 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 方法。它返回一个承诺,当所有可加载组件都准备好时,该承诺将解决。

【讨论】:

  • 可加载组件。没有这样的东西,但我正面临着眨眼。也没有任何东西可以将app.listen 包装在可加载的组件中。
猜你喜欢
  • 1970-01-01
  • 2022-11-11
  • 1970-01-01
  • 1970-01-01
  • 2011-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多