Как отображать асинхронно инициализированные компоненты на сервере
Я относительно новичок в ReactJS и был соблазнен простотой реализации серверной рендеринга, чтобы сократить время до первого твита. Я запускаю стек Node -Express-React, который предварительно создает разметку на сервере с помощью React renderComponentToString.
Он отлично работает, когда компоненты могут отображаться синхронно, однако я боюсь, когда дело доходит до реализации компонентов, заполненных ajax (однако это относится к любой асинхронной операции во время инициализации компонента, например websocket).
Возьмите пример с сайта React: http://facebook.github.io/react/tips/initial-ajax.html
componentDidMount: function() {
$.get(this.props.source, function(result) {
var lastGist = result[0];
this.setState({
username: lastGist.user.login,
lastGistUrl: lastGist.html_url
});
}.bind(this));
Он не будет работать на сервере, поскольку компонент componentDidMount никогда не запускается при использовании renderComponentToString.
Этот простой случай можно обойти, используя ту же самую оболочку HTTP-запроса на клиенте и на сервере (вместо использования jQuery $.get), а также путем предварительной выборки данных до создания экземпляра компонента и передачи его в качестве опоры.
Однако в реальном сложном приложении асинхронные зависимости могут быть очень сложными, и предварительная выборка не очень подходит для потокового подхода к построению структур React.
Как я могу реализовать асинхронный шаблон инициализации в React, который может быть отображен на сервере без фактического монтирования чего-либо (т.е. Эмуляции DOM a la PhantomJS, что является всей точкой использования renderComponentToString)?
Ответы
Ответ 1
Я считаю, что самый практичный способ сделать это - сделать необязательную опору для предварительно загруженных данных, например:
getInitialState: function() {
if (this.props.initialLastGist) {
var lastGist = this.props.initialLastGist;
return {
username: lastGist.user.login,
lastGistUrl: lastGist.html_url
};
} else {
return {};
}
},
componentDidMount: function() {
if (!this.props.initialLastGist) {
$.get(this.props.source, function(result) {
var lastGist = result[0];
this.setState({
username: lastGist.user.login,
lastGistUrl: lastGist.html_url
});
}.bind(this));
}
},
При такой настройке компонент может быть отображен немедленно, если присутствуют предварительно загруженные данные; иначе запрос AJAX будет отправлен при монтаже.
В настоящее время рендеринг сервера всегда синхронный, а componentDidMount
не вызывается на сервере, поскольку он обычно включает манипуляции с DOM. Извините, у меня сейчас нет лучшего решения, но в целом вы хотите минимизировать количество HTTP-запросов на сервер, поэтому стоит подумать о своей архитектуре, чтобы вы могли собрать все данные, которые вам нужны на сервере.
Ответ 2
Вы можете посмотреть проект react-quickstart, который использует react-async
и поставляется с примером рендеринга сервера. react-async
предоставляет декорированный метод renderComponentToString
, который предварительно выбирает асинхронное состояние и отображает его в исходную разметку. Однако вам нужно будет указать асинхронное состояние отдельно от "обычного" состояния.
Ответ 3
вы можете проверить реакцию-nexus (https://github.com/elierotenberg/react-nexus), которая поможет вам заранее объявить все ваши асинхронные зависимости.
но я понимаю, что реакция-нексус - это ваш собственный ответ на эту проблему, поэтому вы, вероятно, уже ее нашли!