0

我正在尝试使用具有数据获取功能的 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, '<\\!--')
    }

});

路线.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);
    });
 }

布局.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;

主页.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;

东西.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;

我错过了什么,误解,做错了什么?

4

1 回答 1

0

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

于 2015-08-03T14:39:43.420 回答