【问题标题】:Server rendering with rails + react-rails gem + react router使用 rails + react-rails gem + react 路由器进行服务器渲染
【发布时间】:2016-06-26 15:29:20
【问题描述】:

我创建了这个示例 repo,它使用 rails (v4.2.6) 和 react-rails (v1.6.2) 和 react-router (v2.0.0-rc5):https://github.com/pioz/rails_with_react_and_react_router_example

在文件app/views/application/react_entry_point.html.erb 中,我使用MountUp 渲染组件

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

组件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>
    )
  }
}

一切正常,但如果我更改选项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'
...

如何渲染这个应用服务器端?这是正确的做法吗?

【问题讨论】:

    标签: ruby-on-rails reactjs react-router react-rails server-rendering


    【解决方案1】:

    找到了解决方案:我们需要两个版本的组件MountUp:一个使用浏览器历史记录的客户端版本和一个使用虚假内存历史记录的服务器版本。这里有两个版本的组件:

    // 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>
        )
      }
    }
    

    我们还需要创建与请求相同的 url 路径的内存历史记录:为此,我们可以向组件传递一个带有请求路径的新 prop path:

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

    【讨论】:

    • 在服务器端的情况下,当页面在客户端呈现时,它仍然使用 memoryHistory,因此如果我们点击一​​个链接,url 不会改变,但内容会改变。有没有办法绕过它?
    • 您需要使用 2 种不同的 Component MountUp,一种用于客户端,一种用于服务器端... application.js 包含 mountup_client.js e server.js 包含 mountup_server.js跨度>
    【解决方案2】:

    我认为告诉它不要预渲染无济于事

    prerender: false
    

    另外,按照它的建议进行操作并获取开发版本,以便它告诉你更多信息

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

    您告诉它基于History 对象构建路由,该对象应该说明用户请求的位置(url)。在服务器端,您将需要以某种方式构造一个对象,该对象将通过一个条目模拟浏览器历史记录:请求的 url。

    我已经在使用 Redux 的节点中使用了这个:

    import createHistory from 'history/lib/createMemoryHistory';
    
    
    var reducer = combineReducers(reducers);
    
    const store = compose(
      applyMiddleware(promiseMiddleware, thunk),
      reduxReactRouter({routes, createHistory})
    )(createStore)(reducer, {});
    

    但您需要采取不同的方法才能将 Rails request 详细信息放入历史存储。

    接下来需要来自开发库的更好的错误消息。

    【讨论】:

      猜你喜欢
      • 2016-04-11
      • 1970-01-01
      • 2017-12-14
      • 2015-04-19
      • 1970-01-01
      • 2016-08-06
      • 2019-10-02
      • 2015-08-18
      • 2020-12-11
      相关资源
      最近更新 更多