简体   繁体   English

使用rails + react-rails gem +反应路由器进行服务器渲染

[英]Server rendering with rails + react-rails gem + react router

I have create this sample repo that use rails (v4.2.6) with react-rails (v1.6.2) and react-router (v2.0.0-rc5): https://github.com/pioz/rails_with_react_and_react_router_example 我创建了这个使用rails(v4.2.6)和react-rails(v1.6.2)以及react-router(v2.0.0-rc5)的示例repo: https//github.com/pioz/rails_with_react_and_react_router_example

In the file app/views/application/react_entry_point.html.erb I render the component MountUp with app/views/application/react_entry_point.html.erb我使用了组件MountUp

<%= react_component('MountUp', {}, {prerender: false}) %>

The component MountUp render my router: 组件MountUp渲染我的路由器:

class MountUp extends React.Component {
  render() {
    return(
      <Router history={History}>
        <Route path="/" component={App}>
          <IndexRoute component={Index} />
          <Route path="/contact" component={Contact}/>
          <Route path="/about" component={About}/>
        </Route>
      </Router>
    )
  }
}

All works fine, but if I change the option prerender: true I get a strange error React::ServerRendering::PrerenderError in Application#react_entry_point : 一切正常,但如果我更改选项prerender: true我得到一个奇怪的错误React::ServerRendering::PrerenderError in Application#react_entry_point

Encountered error "Error: Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings." when prerendering MountUp with {}
Object.invariant [as default] ((execjs):21983:16)
createHashHistory ((execjs):24108:130)
(execjs):22633:20
wrapDeprecatedHistory ((execjs):25285:61)
createRouterObjects ((execjs):25259:23)
componentWillMount ((execjs):25228:38)
ReactCompositeComponentMixin.mountComponent ((execjs):8138:13)
wrapper [as mountComponent] ((execjs):3131:22)
Object.ReactReconciler.mountComponent ((execjs):6583:36)
ReactCompositeComponentMixin.mountComponent ((execjs):8153:35)
/Users/pioz/.rvm/gems/ruby-2.3.0/gems/execjs-2.6.0/lib/execjs/external_runtime.rb:39:in `exec'
...

How can I render this app server side? 如何呈现此应用服务器端? Is this the right way to do this? 这是正确的方法吗?

Found a solution: we need two version of the component MountUp : a client version that use browser history and a server version that use a fake memory history. 找到了解决方案:我们需要两个版本的组件MountUp :使用浏览器历史记录的客户端版本和使用虚假内存历史记录的服务器版本。 Here the two version of the component: 这里有两个版本的组件:

// client version
class MountUp extends React.Component {
  render() {
    return(
      <Router history={History}>
        <Route path="/" component={App}>
          <IndexRoute component={Index} />
          <Route path="/contact" component={Contact}/>
          <Route path="/about" component={About}/>
        </Route>
      </Router>
    )
  }
}


// server version
class MountUp extends React.Component {
  render() {
    return(
      <Router history={createMemoryHistory(this.props.path)}>
        <Route path="/" component={App}>
          <IndexRoute component={Index} />
          <Route path="/contact" component={Contact}/>
          <Route path="/about" component={About}/>
        </Route>
      </Router>
    )
  }
}

We need also to create the memory history with the url path equal to the request: to do this we can pass to the component a new prop path with the path of the request: 我们还需要使用等于请求的url路径创建内存历史记录:为此,我们可以使用请求路径将新的prop path传递给组件:

<%= react_component('MountUp', {path: request.path}, {prerender: true}) %>

I think telling it not to prerender won't help 我认为告诉它不要预先渲染也无济于事

prerender: false

Also, do as it suggests and grab the dev version so it tells you a bit more 另外,按照它的建议并抓住开发版本,它会告诉你更多

use the non-minified dev environment for the full error message

You are telling it to build the routes based on the History object, which is supposed to say where the user has requested to be (the url). 您告诉它基于History对象构建路由,该对象应该说明用户请求的位置(url)。 On the server side, you will need to somehow construct an object that will mimic the browser history with one entry: the requested url. 在服务器端,您将需要以某种方式构造一个对象,该对象将使用一个条目模拟浏览器历史记录:请求的URL。

I have done this in node using Redux using this: 我使用Redux在节点中完成了这个:

import createHistory from 'history/lib/createMemoryHistory';


var reducer = combineReducers(reducers);

const store = compose(
  applyMiddleware(promiseMiddleware, thunk),
  reduxReactRouter({routes, createHistory})
)(createStore)(reducer, {});

But you will need to take a different approach in order to get the Rails request details into the history store. 但是您需要采用不同的方法才能将Rails request详细信息放入历史存储中。

A better error message from the dev library is the next thing you need. 来自开发库的更好的错误消息是您需要的下一件事。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM