Получение данных перед рендерингом на стороне сервера

Прямо сейчас я открываю для себя Este.js, и у меня небольшая проблема с изоморфными приложениями. Я не понимаю, как сделать вызов api перед рендерингом серверной части с помощью renderToString ().

Одно из решений состоит в том, чтобы выполнять выборку всех данных на уровне маршрутизатора с помощью React Router. В зависимости от маршрута верхнего уровня я могу предсказать, какие данные потребуются, сделать вызов api, а затем вызвать React.renderToString.

Отлично, но мне все равно нужно объявить зависимости данных на уровне компонентов И на уровне маршрутизатора. В итоге я дважды пишу один и тот же код и не верю, что это лучший способ сделать это.

РЕДАКТИРОВАТЬ: Хорошо, пока я могу делать то, что хочу. Используя React-Router и эту ссылку, я смог сделать следующее :

Предоставляя это глобальное состояние приложения, я хочу предварительно загружать задачи при указании / задачи

initialstate.js

{
  auth: {
    data: null,
    form: null
  },
  examples: {
    editable: {
      state: null,
      text: 'Some inline-editable text.'
    }
  },
  i18n: {
    formats: {},
    locales: initialLocale,
    messages: messages[initialLocale]
  },
  pendingActions: {},
  todos: {
    editables: {},
    newTodo: {
      title: ''
    },
    list: [{
      id: 1,
      title: 'first todo yipiyo'
    }]
  },
  users: {
    viewer: null
  }
}

todos.react.js

В компоненте todo я объявляю статическую функцию fetchData. Поскольку я хочу получить правильный ключ в своем appState, я передаю list в качестве параметра. Ощущается грязным.

class Todos extends Component {

  static fetchData(){
    return actions.loadAllTodos('list');
  }

  componentDidMount(){
    Todos.fetchData();
  }

  render() {
    ...
  }

}

actions.js

Вызов API и прочее, я передаю ключ к обещанию - кажется хакерским

export function loadAllTodos(key) {

  const promise = new Promise((resolve, reject) => {

    Api.get()
    .then(res => {
      res.key = key; //hacky time
      resolve(res)
    })
    .catch(err => {
      reject(err);
    })

  });

  return dispatch(loadAllTodos, promise);

}

render.js

router.run((Handler, routerState) => {

  var promise = Promise.all(routerState.routes
        .filter(route => route.handler.fetchData)
        .map(route => {
          return route.handler.fetchData();
        })
      );

  promise.then(resp => {

    console.log(resp);

    //Displays : 
    [ { id: 2, title: 'Im a second todo' },{ id: 3, title: 'I like todo' },
    cursor: 'list' ]

    //Some stuff to add resp to appState, using the correct key, yey iso+api=win
    appState = mergeThisWithMagic(appState, resp);

    const html = preloadAppStateThenRenderHtml(Handler, appState);
    const notFound = routerState.routes.some(route => route.name ===
      'not-found');
    const status = notFound ? 404 : 200;
    res.status(status).send(html);
    resolve();

  });


});

Как видите, я создам функцию для обновления appState с помощью обновленного todoList.

Можно ли все это делать? Я хотел бы получить обратную связь, потому что я чувствую, что иду темным путем :(.


person bulby97    schedule 22.06.2015    source источник
comment
Relay решит эту проблему, до тех пор я не уверен, есть ли для этого библиотека. Я определенно думаю, что определение зависимостей данных в компоненте - это правильный путь - вам не нужно повторять это на уровне маршрутизатора, на уровне маршрутизатора вам необходимо собрать зависимости данных от компонентов. Я нашел этот доклад очень полезным на эту тему: youtube.com/watch?v=36ebP9Bf1bk   -  person Dominic    schedule 22.06.2015
comment
Спасибо, посмотрю! Я обновил свой вопрос, не стесняйтесь сказать мне, что вы думаете.   -  person bulby97    schedule 22.06.2015


Ответы (1)


Я сделал это в моем изоморфном приложении на стороне сервера, поместив свои функции fetchData в объект statics компонента (ов) и используя обещания, которые ждут, пока все данные не будут возвращены, прежде чем преобразовать приложение в строку.

Затем вы должны передать возвращенные данные визуализированному компоненту через props. Этот пример сыграл важную роль в моей разработке этого приложения. React Router Mega Demo.

person BradByte    schedule 21.08.2015
comment
Как вы справлялись с избыточными вызовами API? Я использую тот же метод, но также использую componentDidMount для загрузки для рендеринга на стороне клиента. Но они без необходимости увольняются после рендеринга на стороне сервера. - person aray12; 07.06.2016
comment
Отличный вопрос. Во-первых, вы захотите сериализовать данные, которые вы только что получили на сервере, и каким-то образом передать их клиенту. Я использую EJS, но вы можете использовать любой инструмент для создания шаблонов. Затем, когда вы запускаете свой код на стороне клиента, заполните его данными, которые вы только что отправили. Чтобы предотвратить повторяющиеся вызовы, я также реализовал опору cache_once в своем API, чтобы он кэшировал результаты и использовал их вместо другого вызова API. React Router Mega Demo - отличный тому пример. - person BradByte; 07.06.2016