路由和呈现React组件服务器端

时间:2017-02-10 16:03:42

标签: reactjs webpack isomorphic-javascript react-dom react-dom-server

我很难弄清楚我们应该怎样做才能使React同构。我正在学习一些教程,这就是我现在所拥有的:

  • 我创建了一个启动Express服务器的server.js文件
  • 我创建了一个router.js文件,我创建了一个Express Router对象,导入了ReactRouterreact-router)和ReactDOMServerreact-dom/server),然后我设置一个Express路由(router.get('*')),用于获取ReactRouter,试图找到要呈现的路由(ReactRouter.match
  • 出于捆绑目的,我创建了一个包含ReactRouter指令的allRoutes.js文件。我设置了两个路径,//about
  • 两个组件MainAbout,每个组件都有一个按钮和一个点击事件。 Main必须在' /'中呈现和关于' / about'。这两个组件都有HTMLHEADBODY标记,并且它们会重新发送到bundle.js
  • app.js将React设置为DOM中的根元素。
  • Webpack从allRoutes.js文件中创建bundle.js

我遇到了几个问题,第一个是:

  • Main正确呈现并且Javascript工作正常,但转到localhost:3000/about,页面加载需要5秒钟,加载时没有javascript行为,我得到校验和错误。

  • 从/关闭删除bundle.js解决了校验和和繁重的加载问题,但没有Javascript行为

  • 从allRoutes.js捆绑没有出现如上所述的错误,但我没有在页面中使用javascript(虽然它是用bundle.js编写的)

  • 设置/关于/的子路径,因为Main不会导致问题,所以从不加载About组件。如果路由匹配,则服务器仅呈现Main。

正如我计划的那样,但我不确定这是实现同构行为应该做的事情,我在每个根组件About和Main中创建一个完整的HTML页面。在我看来,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(routes.js)更改为此。

<ReactRouter.Router history={ ReactRouter.browserHistory }>
      <ReactRouter.Route path='/' component={ Main } >
        <ReactRouter.Route path='about' component={ About } />
      </ReactRouter.Route>
  </ReactRouter.Router>

现在关于是Main的孩子,Javascript在Main工作,但是从未加载About。尝试访问不存在的路由会显示404,但映射的任何路由都会呈现Main。到底是怎么回事?

@resolved 找到了解决方案:

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

0 个答案:

没有答案