Выборка данных перед рендерингом на стороне сервера

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

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

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

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

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

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, я передаю "список" в качестве параметра. Чувствует себя грязным

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.

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

1 ответ

Решение

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

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

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