J'essaie de configurer le rendu côté serveur pour mon application React et j'essaie d'utiliser le grand module react-router pour lui permettre de gérer des situations non js (certains robots, lorsqu'un l'utilisateur avait désactivé js pour une raison quelconque). Cependant, j'ai des ennuis. J'ai utilisé la grande réponse ici https://stackoverflow.com/a/28558545/3314701 comme guide en quelque sorte, mais je reçois des erreurs étranges. J'obtiens un Syntax Error
Persistant lorsque j'essaie d'utiliser react.renderToString()
. Suis-je en train de configurer le rendu côté serveur de manière incorrecte, manquant quelque chose d’évident ou autre chose?
Ma configuration:
Serveur Express vraiment basique
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});
});
});
Composant de réaction de niveau supérieur <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;
production:
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)
J'ai donc fini par résoudre celui-ci moi-même. L'erreur que j'obtenais venait d'un composant imbriqué non rendu, c'est pourquoi le moteur js se plaignait d'un caractère aléatoire <
.
Et maintenant à ma configuration express. Pour ceux qui ne savent pas comment réagir peut être utilisé avec le rendu côté serveur, c'est assez simple: Node ou io.js peut être utilisé pour appeler la renderToString()
de React sur un composant, puis l'envoyer au client demandeur. Vous avez probablement déjà entendu les avantages de cette approche, mais pour ceux qui ne le savent pas:
Vous pouvez même devenir fou avec cette approche et gérer des choses comme des espaces réservés pour votre application pendant qu'elle se charge ou fournir d'autres mécanismes de rétroaction pour un état de chargement lent (à la Facebook pendant le chargement).
L'approche de base fonctionne grosso modo de la manière suivante:
routes.jsx
req.path
Pour fournir une chaîne de routage à gérer par react-router.routes.jsx
Pour prendre le relais et générer du HTML avec react-router
À partir de maintenant. Un autre avantage ici est que le code de votre application peut être mis en cache et que les interactions futures, espérons-le, n'auront même pas besoin de s'appuyer sur un autre appel.Un autre point à noter: j'utilise webpack pour regrouper mon code de réaction et maintenant browser.jsx
Est le point d'entrée. Avant de refactoriser le rendu côté serveur, il était auparavant app.jsx
; vous devrez peut-être reconfigurer votre structure pour tenir compte de ce qui est rendu où. :)
le Code:
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 (serveur express) :
//...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>
liens utiles: