React 服务器端呈现呈现不正确的内容

React server side rendering renders incorrect content

我正在使用 React、Redux 和 React Router 开发一个带有服务器端渲染(使用 express)的 React Web 应用程序

我面临的问题有点难以解释。我将尝试在以下步骤中对其进行解释。

  1. 您首先从 URL(例如 http://www.example.com/articles/1234)进入应用程序。快递服务器将发送正确的内容,包括正确的页面源和 DOM(来自 chrome 元素面板)作为初始加载。

  2. 然后让我们导航到另一个页面,例如 http://www.example.com/articles/5678(导航不会导致页面刷新,因为它是一个单页应用程序,它只会在您这样做时到达服务器以获取 SSR 内容使用浏览器刷新或从浏览器地址栏中的 URL 进入页面)到目前为止一切正常。

  3. 使用 cmd + r 或 F5 在浏览器中刷新页面(您现在位于页面 http://www.example.com/articles/5678)。同样,服务器将发送内容。但这次您收到的内容有点不同。浏览器中的页面内容以及 chrome 元素面板中的 DOM 都是正确的。但是,页面源不正确,它仍然是您从步骤 1 获得的旧页面源。

我尝试在刷新页面时注销内容。服务器在第 3 步中发送下来的内容不是正确的内容(它是上一页)但是不知何故浏览器仍然可以看到正确的内容。

如果我在第 3 步之后再次刷新页面,那么我将获得正确的内容和正确的页面源...

我也在使用 Facebook 开放图调试器。调试器告诉我它跟随重定向到第 3 步。它跟随的重定向 URL 是上一页 URL。我知道这不太对,但不确定我哪里做错了...

这是我的快速服务器设置

感谢您的帮助!

server.js

require('babel-register');
const express = require('express');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const ReactRouter = require('react-router');
const ReactRedux = require('react-redux');
const Store = require('./src/store/configureStore').default;
const routes = require('./src/routes').default;
const compression = require('compression');
const morgan = require('morgan');

const store = Store();
const match = ReactRouter.match;
const RouterContext = ReactRouter.RouterContext;
const Provider = ReactRedux.Provider;
const port = process.env.PORT || 5050;
const ReactHelmet = require('react-helmet');

const Helmet = ReactHelmet.Helmet;

const app = express();
app.use('/dist', express.static('./dist'));

app.set('view engine', 'ejs');

app.use(compression());
app.use(morgan('combined'));

app.use((req, res) => {
  // prettier-ignore
  match(
    { routes, location: req.url },
    (error, redirectLocation, renderProps) => {
      if (error) {
        res.status(500).send(error.message);
      } else if (redirectLocation) {
        res.redirect(302, redirectLocation.pathname + redirectLocation.search);
      } else if (renderProps) {
        console.log(renderProps);
        const body = ReactDOMServer.renderToString(
          React.createElement(
            Provider,
            { store },
            React.createElement(RouterContext, renderProps)
          )
        );
        const meta = Helmet.renderStatic().meta.toString();
        res.status(200).render('index', {body, meta});
      } else {
        res.status(404).send('Not found');
      }
    }
  );
});

console.log('listening on port ' + port); // eslint-disable-line

app.listen(port);

我最终解决了这个问题。

主要问题是我将异步数据获取调用置于 componentWillMount 生命周期方法中,而不是 componentDidMount

而且我没有在我的应用程序中正确处理异步数据获取。

我现在正在使用 this article 中提到的方法来处理我的异步数据获取问题。

基本上,我在做以下事情:

  1. 客户端:在组件中创建一个静态方法fetchData

  2. 服务端:使用React Router抓取正确的组件,使用fetchData方法获取该组件需要的数据

  3. 在这些承诺得到解决后,从 Redux store 获取当前状态并呈现 HTML 并将其发送给客户端。

  4. 将状态注入客户端 Redux 存储并呈现页面。