Рендеринг сервера с помощью rails + response-rails gem + реакции маршрутизатора

Я создал этот репозиторий, который использует rails (v4.2.6) с response-rails (v1.6.2) и response-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'
...

Как я могу сделать это приложение на стороне сервера? Это правильный способ сделать это?

2 ответа

Решение

Нашли решение: нам нужны две версии компонента 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-адресом, равным запросу: для этого мы можем передать компоненту новый объект. path с путем запроса:

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

Я думаю, что говорить не предаваться не поможет

prerender: false

Кроме того, сделайте, как он предлагает, и получите версию dev, чтобы она рассказывала вам немного больше

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 подробности в истории магазина.

Лучшее сообщение об ошибке из библиотеки dev - следующее, что вам нужно.

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