服务器端渲染与反应,反应路由器和快递 [英] Server side rendering with react, react-router, and express

查看:106
本文介绍了服务器端渲染与反应,反应路由器和快递的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为我的应用程式设置服务器端呈现,而我正在尝试使用很棒的反应路由器模块,以允许它处理非js情况(某些抓取工具,当用户由于某些原因关闭了js)时。但是,我遇到麻烦。我一直在使用伟大的回应 https://stackoverflow.com/a/28558545/3314701 作为指导排序,但我正在收到奇怪的错误。尝试使用 react.renderToString()时,会得到一个持久的语法错误。我设置的服务器端呈现错误,缺少一些明显的东西,还是其他什么?

I'm trying to set up server-side rendering for my react app and I'm trying to use the great react-router module to allow it to handle non-js situations (some crawlers, when a user had js turned off for some reason). However, I'm running into trouble. I've been using the great response here https://stackoverflow.com/a/28558545/3314701 as a guide of sorts, but I'm getting strange errors thrown at me. I get a persistent Syntax Error when trying to use react.renderToString(). Am I setting up the server-side rendering incorrectly, missing something obvious, or anything else?

我的设置:

基本的Express服务器

require('babel/register');

var app = express();


// misc. express config...

var Router = require('react-router'),
    routes = require('../jsx/app').routes,
    React = require('react');


app.use(function(req, res, next) {
  var router = Router.create({location: req.url, routes: routes});
  router.run(function(Handler, state) {
    console.log(Handler);
    var html = React.renderToString(<Handler/>);
    return res.render('react_page', {html: html});
  });
});

顶级反应< App /> 组件

Top-level react <App/> component

// Shims
require('intl');
require('es5-shim');

var React = require('react/addons'),
  Router = require('react-router'),
  Nav = require('./nav'),
  injectTapEventPlugin = require("react-tap-event-plugin"),


  window.React = React; // export for http://fb.me/react-devtools

// Intl
var ReactIntl = require('react-intl'),
  IntlMixin = ReactIntl.IntlMixin;

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


var App = React.createClass({
      mixins: [IntlMixin],

      getInitialState: function() {
        return {
          connected: false,
          loaded: false,
          user: true
        };
      },
      render: function() {
          return ( 
            <div className="container-fluid">
              <Nav/>
              <RouteHandler/>
              <Footer/>
            </div>
      );
  }

});

var routes = (
<Route name="Home" path="/" handler={App}>
    <DefaultRoute name="Welcome " handler={Welcome}/>
    <Route name="Bar" path="/bar" handler={Bar}>
    <Route name="foo" path="/foo" handler={Foo}></Route>
 </Route>
);

Router.run(routes, Router.HistoryLocation , function(Handler) {
  React.render(<Handler/>, document.getElementById('app'));
});

module.routes = routes;

输出:

flo-0,1,2 (err):       <div className="progressbar-container" >
flo-0,1,2 (err):       ^
flo-0,1,2 (err): SyntaxError: Unexpected token <
flo-0,1,2 (err):     at exports.runInThisContext (vm.js:73:16)
flo-0,1,2 (err):     at Module._compile (module.js:443:25)
flo-0,1,2 (err):     at Module._extensions..js (module.js:478:10)
flo-0,1,2 (err):     at Object.require.extensions.(anonymous function) [as .js] (/Users/user/Code/foobar/apps/flo/node_modules/babel/node_modules/babel-core/lib/babel/api/register/node.js:161:7)
flo-0,1,2 (err):     at Module.load (module.js:355:32)
flo-0,1,2 (err):     at Function.Module._load (module.js:310:12)
flo-0,1,2 (err):     at Function.<anonymous> (/Users/user/.nvm/versions/node/v0.12.4/lib/node_modules/pm2/node_modules/pmx/lib/transaction.js:62:21)
flo-0,1,2 (err):     at Function.cls_wrapMethod (/Users/user/Code/foobar/apps/bar/node_modules/newrelic/lib/shimmer.js:230:38)
flo-0,1,2 (err):     at Function.<anonymous> (/Users/user/Code/foobar/apps/bar/node_modules/pmx/lib/transaction.js:62:21)
flo-0,1,2 (err):     at Module.require (module.js:365:17)
flo-0,1,2 (err):     at require (module.js:384:17)


推荐答案

所以,我最终自己解决了这个问题。我得到的错误是从未渲染的嵌套组件,这就是为什么js引擎抱怨一个随机的< char。

So, I ended up solving this one myself. The error I was getting was from an un-rendered nested component, which is why the js engine was complaining about a random < char.

现在到我的快捷设置。对于那些不知道如何使用服务器端渲染的人来说,这是非常简单的:Node或io.js可以用来调用React的 renderToString()方法,然后将其发送到请求的客户端。您可能已经听说过这种方法带来的好处,但对于那些不了解的人来说:

And now to my express setup. For those who aren't aware of how react can be used with server-side rendering, it's fairly straightforward: Node or io.js can be used to call React's renderToString() method on a component and then sending that to the requesting client. You've probably heard the benefits this approach brings already, but for those who don't know:


  1. 您可以获得更多的SEO友善性,即使谷歌可以在其抓取器中执行JS;这非常只是一个更安全的赌注

  2. 非js情况的回退。如果您的应用脚本缓慢加载,您仍然可以将实际页面呈现给客户端,而不要让其等待,而盯着空白屏幕。这也允许在浏览器上禁用JS的人大部分仍然与您的应用程序进行交互;链接仍然可以工作,表单仍然可以提交,< c。

  3. 您可以在客户端和服务器之间获得代码共享的额外优势。除了复杂性降低的事实之外,没有必要令人难以置信,因此,您可以获得复杂性降低的所有好处(潜在地减少耦合,更易于维护,更简单的结构,同构性和同等性) / li>
  4. 另一个好处是可以使用反应路由器的html5历史API,而不是使用烦人的哈希片段的东西,否则可以使用。

您甚至可以通过这种方法疯狂处理您的应用程序的占位符,同时加载或提供其他缓慢加载状态的反馈机制(在加载Facebook时)

You could even get crazy with this approach and handle things like placeholders for your app while it loads or provide other feedback mechanisms for a slow-loading state (a la Facebook while it loads).

基本方法的操作大致如下:

The basic approach operates roughly in the following manner:


  1. 引导,节点应用程序根据 routes.jsx实例化一个反应路由器实例

  2. 请求转到服务器,然后使用express req.path 提供一个路由字符串反应路由器来处理。

  3. 反应路由器然后匹配提供的路由,并尝试呈现相应的组件以进行快速发送。

  4. 反应发送html响应,您的客户端可以绘制某些东西,而不管应用脚本的速度如何。我们服务于一个伟大的CDN,但即使最好的分布和压缩慢网络仍然会让人们暂时空白屏幕。

  5. 加载所需的应用脚本后,React可以使用相同的 routes.jsx 文件来接管并使用 react-router 从这里出来。这里的另一个好处是,您的应用程序代码可以被缓存,并且将来的交互希望甚至不需要依赖另一个调用。

  1. Upon bootstrap, the node app instantiates a react-router instance based on routes.jsx
  2. Request goes to the server, which then uses express' req.path to provide a route string for react-router to handle.
  3. React router then matches the provided route and tries to render the corresponding component for express to send back.
  4. React sends down the html response and your client gets to paint something regardless of the speed of your app script. We serve ours over a great CDN, but even with the best distribution and compression slow networks would still otherwise leave people with a temporarily blank screen.
  5. Having loaded the needed app script, React can use the same routes.jsx file to take over and generate html with react-router from here on out. Another benefit here is that your app code can be cached and future interactions hopefully won't even have to rely on another call.

还有一点值得注意:我使用webpack捆绑我的反应代码,现在 browser.jsx 是入口点。在重构服务器端渲染之前,它以前是 app.jsx ;您可能需要重新配置您的结构以适应所呈现的位置。 :)

One more point worth noting: I use webpack to bundle my react code and now browser.jsx is the entry point. Before refactoring for server-side rendering it was previously app.jsx; you might need to re-configure your structure to accommodate what gets rendered where. :)

le代码:

Browser.jsx

const React = require('react');
const Router = require('react-router').Router;
const hist = require('history');
const routes = require('./routes');

const newHistory = hist.createHistory();

React.render(<Router history={newHistory}>{routes}</Router>, window.document);

App.js(express server)

//...other express configuration

const routes = require('../jsx/routes');
const React = require('react');
const {RoutingContext, match} = require('react-router');
const hist = require('history');

app.use((req, res, next) => {
  const location = hist.createLocation(req.path);
  match({
    routes: routes,
    location: location,
  }, (err, redirectLocation, renderProps) => {
    if (redirectLocation) {
      res.redirect(301, redirectLocation.pathname + redirectLocation.search);
    } else if (err) {
      console.log(err);
      next(err);
      // res.send(500, error.message);
    } else if (renderProps === null) {
      res.status(404)
        .send('Not found');
    } else {
      res.send('<!DOCTYPE html>' + React.renderToString(<RoutingContext {...renderProps}/>));
    }
  });
});

    //...other express configuration

路线。 jsx

<Route path="/" component={App}>
  <DefaultRoute component={Welcome}/>
  <Route path="dashboard" component={Dashboard}/>
  <Route path="login" component={Login}/>
</Route>

App.jsx

<html>
<head>
  <link rel="stylesheet" href="/assets/styles/app.css"/>
</head>
  <body>
    <Navigation/>
    <RouteHandler/>
    <Footer/>
  <body/>
</html>

有用的链接:

  • https://ifelse.io/2015/08/27/server-side-rendering-with-react-and-react-router/
  • https://github.com/rackt/react-router

这篇关于服务器端渲染与反应,反应路由器和快递的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆