ReactJS react-router服务器渲染问题

时间:2016-01-13 15:50:34

标签: javascript reactjs react-router

一切都是关于同构应用。我在服务器端使用int i = 9;React模块进行路由,并在浏览器控制台中发出以下警告。

  

警告:渲染(...):用新的替换React渲染的子项   根组件。如果您打算更新此节点的子节点,   你应该让现有的孩子更新他们的状态和   渲染新组件而不是调用ReactDOM.render。

我在后端

上定义了以下路线模式
react-router

应用程序组件:

<Route path="/" component={App} >
    <IndexRoute component={Home} />
</Route>

主页组件:

module.exports = React.createClass({
  render : function() {
    return <html>
      <head></head>
      <body>        
        <div id="container">
          { this.props.children }
        </div>        
        <script src="/app/bundle.js"></script>
      </body>
    </html>
  }
});

之后我使用前端

module.exports = React.createClass({
  render : function() {
    return <div>Any content here</div>
  }
});

可能的解决方案: 如果我理解正确,我可以将App组件呈现为静态标记(ReactDOM.render(<Home />, document.getElementById('container')); )而将Home组件呈现为字符串(renderToStaticMarkup),那么它就可以了。

是否可以使用renderToString实现类似的内容?

1 个答案:

答案 0 :(得分:3)

假设RR 1.03,您的路由配置看起来很好。

您的应用组件应如下所示:

module.exports = React.createClass({
  render : function() {
    return <html>
      <head></head>
      <body>        
        <div id="container">
          {React.cloneElement(this.props.children,
            {
              anyOtherPropsHere: 'blablah'
            }
          )}
        </div>        
        <script src="/app/bundle.js"></script>
      </body>
    </html>
  }
});

您的服务器响应 - &gt;渲染应该看起来像这样。 (取自documentation

import { renderToString } from 'react-dom/server'
import { match, RouterContext } from 'react-router'
import routes from './routes'

serve((req, res) => {
  // Note that req.url here should be the full URL path from
  // the original request, including the query string.
  match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
    if (error) {
      res.status(500).send(error.message)
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search)
    } else if (renderProps) {
      // You can also check renderProps.components or renderProps.routes for
      // your "not found" component or route respectively, and send a 404 as
      // below, if you're using a catch-all route.
      res.status(200).send(renderToString(<RouterContext {...renderProps} />))
    } else {
      res.status(404).send('Not found')
    }
  })
})

最后,在客户端加载的某个地方,做这样的事情。我在此示例中添加了history库以提供帮助。

import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, match, RoutingContext } from 'react-router';
import history from 'utils/history';
import AppRoutes from '/app/AppRoutes';

// use this function to return a Route component with the right props
function createFluxComponent(Component, props) {
    props = Object.assign(props, {
        flux: window.flux.or.whatevs
    });

    return <Component {...props} />;
}

// add a global history listener perhaps?
history.listen(function(location) {
    console.log('Transition to--------------', location.pathname);
});

// add window.router polyfill for transitionTo
window.router = {
    transitionTo: function(t) {
        return history.pushState(null, t);
    }
};

// render your routing configuration, history and flux as  props
ReactDOM.render(<Router createElement={createFluxComponent} history={history} routes={AppRoutes}/>, document);

最重要的是使用RouterContext渲染到字符串并在服务器端渲染道具。您可以从RR匹配函数获取renderProps,它将针对配置运行您的路由并在renderProps中生成正确的组件。然后,您只需使用Router元素向客户端呈现,并将路由器配置呈现给文档。这有意义吗?它应该没有任何不变量。