私は私のreactアプリのサーバーサイドレンダリングを設定しようとしていますが、素晴らしい react-router モジュールを使用して、非jsの状況(一部のクローラー、ユーザーは何らかの理由でjsをオフにしました)。しかし、私は問題に直面しています。私はここで素晴らしい応答を使用していました https://stackoverflow.com/a/28558545/3314701 種類のガイドとして、しかし奇妙なエラーが私に投げられています。 react.renderToString()
を使用しようとすると、永続的なSyntax Error
を取得します。サーバー側のレンダリングを誤って設定しているか、明らかなものが欠落しているか、または他に何かがありますか?
私のセットアップ:
本当に基本的な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/>
コンポーネント
// 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について文句を言っていました。
そして今、私の急行のセットアップに。サーバー側レンダリングでreactをどのように使用できるかを知らない人にとっては、かなり簡単です:Nodeまたはio.jsを使用してReactのrenderToString()
を呼び出すことができますメソッドをコンポーネントに送信してから、それを要求元のクライアントに送信します。おそらく、このアプローチがもたらすメリットは聞いたことがあるでしょう。
このアプローチに夢中になり、ロード中にアプリのプレースホルダーなどを処理したり、ロードの遅い状態(ロード中のFacebookなど)に他のフィードバックメカニズムを提供したりすることもできます。
基本的なアプローチは、おおよそ次のように動作します。
routes.jsx
_に基づいて反応ルーターインスタンスをインスタンス化しますreq.path
_を使用して、反応するルーターが処理するルート文字列を提供します。routes.jsx
_ファイルを使用して、これから_react-router
_でhtmlを引き継いで生成できます。ここでのもう1つの利点は、アプリのコードをキャッシュすることができ、将来のインタラクションが別の呼び出しに依存する必要さえないことを願っています。注目に値するもう1つのポイント:webpackを使用して反応コードをバンドルすると、_browser.jsx
_がエントリポイントになります。サーバー側レンダリングのリファクタリング前は、以前は_app.jsx
_でした。どこでレンダリングされるものに対応するために、構造を再構成する必要があるかもしれません。 :)
コード:
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(エクスプレスサーバー):
_//...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
_
Routes.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>
_
便利なリンク: