【问题标题】:Using server-side-render only for initial page load仅将服务器端渲染用于初始页面加载
【发布时间】:2016-07-08 14:50:05
【问题描述】:

我想使用 react 的服务器端渲染来仅获取用户的初始状态。之后,我更喜欢使用 websockets/ajax/客户端路由来处理应用程序。

这是我目前所拥有的

 function handleRender(req,res){

    getInitialState(id_token)
      .then(function(initialState){
        const store = createStore(rootReducer,initialState)
        console.log('store.getState() ',store.getState())
        const html = renderToString(
          <Provider store={store}>
            <App/>
          </Provider>
        )
        res.send(renderFullPage(html,initialState))
      })
      .catch(function(err){
        console.log('error')
      })
  }

  const renderFullPage = (html,initialState) => {
    return `
      <!doctype html>
      <html>
        <head>
          <title>Redux Universal</title>
        </head>
        <body>
          <div id="app"><div>${html}</div></div>
          <script>
            window.__INITIAL_STATE__= ${JSON.stringify(initialState)}
          </script>
          <script src="/bundle.js"></script>
        </body>
      </html>`
  }

我的客户端 index.js 非常标准

const initialState = window.__INITIAL_STATE__

export const store = createStore(rootReducer,initialState)


ReactDOM.render(
  <Provider store={store}>
    <Router history={browserHistory}>
      <Route path="/" component={App} />
      <Route path ="/project" component={Project} />
    </Router>
  </Provider>
  ,document.getElementById('app')
)

上面的效果很好。当我导航到客户端的 /project 时。 Project 组件呈现。

但是,当我在 /project 刷新页面时,我会在客户端路由器移动到 /project 之前快速呈现 / 页面。

另外,每当我在路由之间切换时,我都会再次访问我不想要的服务器。

我知道这应该发生,因为刷新再次命中服务器导致它发回

<Provider store={store}>
    <App/>
  </Provider>

渲染 app 组件,之后 react-router 再次渲染 /project 组件。

有没有一种方法可以让我从服务器获取window.__INITIAL_STATE__ 和初始 HTML,而不必在每次刷新/路由更改时发送 html。

我不想在每次路由更改时都访问服务器,这是我相信的普遍反应。

对我来说最重要的是在页面加载时为用户获取初始状态。我更喜欢将应用程序用作水疗中心(仅针对初始渲染/状态和 api 请求访问服务器)

【问题讨论】:

  • handleRender 在哪里被调用?
  • “另外,每当我在路由之间切换时,我都会再次访问我不想要的服务器。”。请为我澄清这一点。带有 react-router 的 SPA 和其中的链接不会导致窗口刷新,也不会“在每次路由更改时访问服务器”
  • @idbehold - handlerender 设置为快速中间件 - app.use(handleRender)
  • @Yozi - 由于某种原因,路由更改正在影响服务器:( .. 你认为这可能是因为我没有渲染路由器上下文以及初始状态吗?
  • @Kunkka,我认为这可能是一个严重错误或类似的错误,请在控制台中检查。你的客户端渲染看起来是正确的,我的差不多

标签: javascript reactjs react-router


【解决方案1】:

我很确定您错过了将服务器端请求的路由与您的 react 路由器中的路由相匹配的部分。

import { RoutingContext, match } from 'react-router';
import createLocation from 'history/lib/createLocation';
import routes from './react-routes';

app.get('/*', (req, res, next) => {
  // create a "location" object from the requested url
  const location = createLocation(req.url);

  // match the location to the react routes we have
  match({ routes, location }, (err, redirect, renderProps) => {
    if (err) {
      console.error(err);
      return res.status(500).end('Internal server error');
    }

    if (!renderProps) return res.status(404).end('Not found');

    getInitialState(id_token).then((initialState) => {
      const store = createStore(rootReducer,initialState);
      const html = renderToString(
        <Provider store={store}>
          {() =>
            <RoutingContext {...renderProps} />
          }
        </Provider>
      );
      res.send(renderFullPage(html,initialState));
    });
  });
});

查看this isomorphic redux example app。并非所有情况都适用于您的情况,但请查看 server.jsclient.jsroutes.js

【讨论】:

  • 这是否意味着我在每个 url 请求上都会访问服务器?即使是 /projects?
  • @Kunkka 只要您使用&lt;Link&gt; 元素在您的网站上导航,那么就不会。 &lt;Link&gt; 元素将使用您的反应路由器来更改页面上的内容。除非您明确刷新页面或在新选项卡中打开链接,否则它不会加载整个页面。
  • @Kunkka 例如,如果您打开一个新选项卡,然后输入 yoursite.com/foo 那么您的服务器将生成并发送该页面的 HTML。如果您然后单击转到 /bar 的 &lt;Link&gt;,那么您应该会看到地址栏更新以反映该导航,但是您不会进行整页加载。监控您的网络流量,您将看到没有向 yoursite.com/bar 发出请求。
猜你喜欢
  • 2016-08-27
  • 1970-01-01
  • 1970-01-01
  • 2016-04-03
  • 2021-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多