Маршрутизация и рендеринг компонентов 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 нашел решение:

https://github.com/victorsferreira/react-isormorphic/

0 ответов

Другие вопросы по тегам