【问题标题】:React-router server-side rendering on each page每个页面上的 React-router 服务器端渲染
【发布时间】:2015-08-03 09:18:35
【问题描述】:

我正在尝试使用 express 和 react-router 构建一个同构应用程序,并使用数据获取和首先呈现服务器端和数据操作客户端。

我设法获取初始数据服务器端并渲染 jsx 组件,但它仅在直接点击 url 时才有效,而不是跟随链接。事实上,正如我读过的所有示例一样,应用程序只在服务器端渲染一次,然后一切都发生在客户端。

另外,如果我获取一些数据,渲染一个组件服务器端然后点击一个链接,新页面的数据不会更新。

我不知道我是不是在尝试做一些没有意义的事情?

我想得到的是:

  • 每个页面的预渲染服务器端,无论用户是直接到达还是通过链接到达
  • 仅获取 与路由对应的组件要求的初始数据
  • [BONUS] 应用对组件布局的小改动(标题、附加 css 等)

这是我目前所拥有的:

快递应用:

var express = require('express');
require('node-jsx').install();
var React = require('react');  
var Router = require('react-router'); 
var routes = require('./routes');
var url  = require('url');
var resolveHash = require('when/keys').all;


var app = express();

/*
 ....
*/

app.use(function(req, res, next) {
  Router.run(routes, url.parse(req.url).pathname, function(Handler, state){
      // create the promises hash
      var promises = state.routes.filter(function (route) {
        // gather up the handlers that have a static `fetchData` method
        return route.handler.fetchData;
      }).reduce(function (promises, route) {
        // reduce to a hash of `key:promise`
        promises = route.handler.fetchData(state.params);
        return promises;
      }, {});

      resolveHash(promises).then(function (data) {
        var html = '<!DOCTYPE html>' + React.renderToString(React.createFactory(Handler)({path:url.parse(req.url).pathname, initialData:safeStringify(data)}));
        res.send(html);
      });
    });

  // A utility function to safely escape JSON for embedding in a <script> tag
    function safeStringify(obj) {
      return JSON.stringify(obj).replace(/<\/script/g, '<\\/script').replace(/<!--/g, '<\\!--')
    }

});

routes.js:

var React = require("react");
var Router = require("react-router");

var Route = Router.Route;
var DefaultRoute = Router.DefaultRoute;
var NotFoundRoute = Router.NotFoundRoute;

var Layout = require("./components/layout.jsx");
var Stuff = require("./components/stuff.jsx");
var Home = require("./components/home.jsx");

var routes = (  
  <Route path="/" handler={Layout}>
    <Route path="/stuff" handler={Stuff} />
    <DefaultRoute handler={Home}/>
  </Route>
);

module.exports = routes;

if (typeof document !== 'undefined') { 
  var initialData = JSON.parse(document.getElementById("initialData").innerHTML);
    Router.run(routes, Router.HistoryLocation, function (Handler) {
      React.render(<Handler initialData={initialData}/>, document);
    });
 }

layout.jsx:

'use strict';  
var React = require('react');  
var Router = require('react-router');  
var RouteHandler = Router.RouteHandler;  
var Link = Router.Link;

var Layout = React.createClass({  
  render: function () {
    return (
      <html>
        <head>
          <title>{this.props.initialData.title}</title>
        </head>
        <body>
          <nav>
            <Link to={'/'}>Home</Link>
            <Link to={'/stuff'}>Stuff</Link>
          </nav>
          <RouteHandler/>
          <script id='initialData' type="application/json" dangerouslySetInnerHTML={{__html:this.props.initialData}}></script>
          // actually bundle.js is just made of routes.js as I put the client side render there
          <script src="/bundle.js"></script>
        </body>
      </html>
    );
  }
});


module.exports = Layout;

home.jsx:

'use strict';  
var React = require('react');

var Home = React.createClass({  

  statics: {
    fetchData: function(params){
      return {test:[1,2,3], title:'Home'};
    }
  },

  render: function () {
    return (
      <div className="content">
        <section>
          <article>
            <h2>Title</h2>
            <p>Body</p>
          </article>
        </section>
        <aside>
          Ads
        </aside>
      </div>
    );
  }
})

module.exports = Home;

stuff.jsx:

'use strict';  
var React = require('react');

var Stuff = React.createClass({  

    statics: {
    fetchData: function(params){
      return {test:[4,5,6], title:'Stuff'};
    }
  },

  render: function(){
    return (<h1>Hello world from thingy!</h1>)
  }
})

module.exports = Stuff;

我遗漏了什么、误解、做错了什么?

【问题讨论】:

    标签: express reactjs server-side react-router isomorphic-javascript


    【解决方案1】:

    这就是它的工作方式,它会让您首先加载并构建该 html 并呈现它,然后它无法更改生成的 html,除非您通过单击刷新页面刷新按钮或让您的代码window.location

    【讨论】:

    • 有没有办法在渲染之前为每个组件加载正确的初始数据?
    • 恐怕不会有什么不同,因为它将是 Javascript 并且不会改变打印到浏览器的内容。
    • 你的意思是唯一的入口 URL 是根 URL?
    • 不确定你的意思。在服务器上,您应该镜像您的链接,以防有人直接访问您的子页面之一。如果您不这样做,则页面将不会呈现。所以如果你有 http://.../about/ 你应该有一个从服务器直接到那个页面的路由,这样它就可以被正确地提供,否则它不会。
    猜你喜欢
    • 2018-01-06
    • 1970-01-01
    • 1970-01-01
    • 2016-03-26
    • 2016-11-17
    • 1970-01-01
    • 2017-08-31
    • 2016-08-06
    • 1970-01-01
    相关资源
    最近更新 更多