Маршрутизация и рендеринг компонентов React на стороне сервера
Мне очень трудно понять, что нам нужно сделать, чтобы сделать React изоморфной. Я следую некоторым урокам, и вот что у меня сейчас:
- Я создал
server.js
файл, который запускает сервер Express - Я создал
router.js
файл, в котором я создал объект Express Router, импортировалReactRouter
(react-router
) а такжеReactDOMServer
(react-dom/server
) и там я установил экспресс-маршрут (router.get('*')
) который выбирает ReactRouter, пытаясь найти маршрут для рендеринга (ReactRouter.match
) - Для объединения я создал файл allRoutes.js, который содержит
ReactRouter
директивы. Я установил два пути,/
а также/about
- Два компонента,
Main
а такжеAbout
каждый с кнопкой и событием щелчка.Main
должно быть отображено в '/' и About в '/about'. Оба компонента имеютHTML
,HEAD
а такжеBODY
теги и они перезаписываютсяbundle.js
- app.js, который устанавливает React для корневого элемента в DOM.
- Webpack для создания
bundle.js
из файла allRoutes.js
Я столкнулся с несколькими проблемами, первая была:
Main правильно отображается и Javascript работает нормально, но собирается
localhost:3000/about
загрузка страницы занимает около 5 секунд, она загружается без поведения JavaScript, и я получаю ошибку контрольной суммы.Удаление bundle.js из / about решает проблемы с контрольной суммой и тяжелой загрузкой, но поведение Javascript отсутствует
Пакетирование из allRoutes.js не дает ошибок, подобных описанным выше, но у меня нет javascript, работающего на странице (хотя он написан в bundle.js)
Установка / about как дочернего маршрута для /, так как Main не вызывает проблем, никогда не загружает компонент About. Сервер только отображает Main, если маршрут соответствует.
Как я планировал, но я не уверен, что это то, что я должен сделать для достижения изоморфного поведения, я создаю целую HTML-страницу в каждом из этих корневых компонентов, About и Main. Это кажется мне более дружественным SEO.
Я что-то не так делаю?
app.js
var React = require('react');
var ReactDOM = require('react-dom');
var Main = require('./components/Main');
ReactDOM.render(React.createElement(Main),document);
router.js
var express = require('express');
var router = express.Router();
var ReactRouter = require('react-router');
var ReactDOMServer = require('react-dom/server');
var Main = require('./components/Main');
var About = require('./components/About');
var React = require('react');
var routes = require('./routes');
router.get('*', function (req, res) {
var props = {};
ReactRouter.match({
routes: (
routes
),
location: req.url
}, function (error, redirectLocation, renderProps) {
console.log(renderProps)
if (renderProps) {
// se encontrou uma rota, responde o HTML referente ao componente que foi preprocessado no backend
res.send(ReactDOMServer.renderToString(
<ReactRouter.RouterContext {...renderProps} createElement={
function(Component,renderProps){
return <Component {...renderProps} {...props} />
}
} />
));
} else {
res.status(404).send('Not found');
}
});
});
module.exports = router;
routes.js
//routes.js
var ReactRouter = require('react-router');
var React = require('react');
var Main = require('./components/Main');
var About = require('./components/About');
module.exports = (
<ReactRouter.Router history={ ReactRouter.browserHistory }>
<ReactRouter.Route path='/' component={ Main } />
<ReactRouter.Route path='/about' component={ About } />
</ReactRouter.Router>
);
WebPack
module.exports = {
entry: './routes.js',
output: {
filename: './bundle.js',
path: 'public'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react']
}
}
]
}
};
about.js
var React = require('react');
module.exports = React.createClass({
_handleClick: function(){
alert('Sobre!');
},
render: function(){
return (
<html>
<head>
<link rel='stylesheet' href='/style.css' />
</head>
<body>
<h1>About</h1>
<button onClick={ this._handleClick }>About</button>
<script src='/bundle.js'></script>
</body>
</html>
);
}
});
server.js
require('babel-register')({
presets: ['react']
});
var React = require('react');
var ReactDOMServer = require('react-dom/server');
var express = require('express');
var app = express();
app.use(express.static('./public'));
app.use(require('./router'));
app.listen(3000,function(){
console.log('Started at 3000');
});
@editing
Я изменил allRoutes (rout.js) на это.
<ReactRouter.Router history={ ReactRouter.browserHistory }>
<ReactRouter.Route path='/' component={ Main } >
<ReactRouter.Route path='about' component={ About } />
</ReactRouter.Route>
</ReactRouter.Router>
Теперь About является дочерним элементом Main, Javascript работает в Main, но About никогда не загружается. Попытка получить доступ к несуществующему маршруту показывает мне 404, но любой сопоставленный маршрут отображает Main. Что здесь происходит?
@resolved нашел решение: