React + Flux и Server-side рендеринг? (Изоморфный реактив + поток)
Какова общая практика установки начального состояния приложения с изоморфными приложениями? Без Flux я бы просто использовал что-то вроде:
var props = { }; // initial state
var html = React.renderToString(MyComponent(props);
Затем визуализируйте эту разметку через express-handlebars и отобразите ее с помощью {{{reactMarkup}}
.
На стороне клиента, чтобы установить начальное состояние, я сделал бы что-то вроде этого:
if (typeof window !== 'undefined') {
var props = JSON.parse(document.getElementById('props').innerHTML);
React.render(MyComponent(props), document.getElementById('reactMarkup'));
}
Итак, да, в основном вы устанавливаете состояние дважды, на сервере и клиенте, однако React будет сравнивать различия и в большинстве случаев, поэтому это не повлияет на производительность путем повторной рендеринга.
Как этот принцип будет работать, когда у вас есть действия и магазины в архитектуре Flux? Внутри моего компонента я мог сделать:
getInitialState: function() {
return AppStore.getAppState();
}
Но как установить начальное состояние в AppStore с сервера? Если я использую React.renderToString
без переданных свойств, он вызовет AppStore.getAppState()
, у которого ничего не будет, потому что я все еще не понимаю, как установить состояние в моем хранилище на сервере?
Обновление 5 февраля 2015 г.
Я все еще ищу чистое решение, которое не связано с использованием сторонних реализаций Flux, таких как Fluxible, Fluxxor, Reflux.
Обновление 19 августа 2016 г.
Используйте Redux.
![]()
Ответы
Ответ 1
Если вы готовы работать с alt.js, вы можете достичь этого с помощью alt.bootstrap
и alt.flush
(docs)
Я использую node js с реакцией на стороне сервера, а alt.js - на реализацию потока.
Вот как это выглядит:
var data = {}; // Get the data whatever you want and return it bootstrap ready.
// Reminder - renderToString is synchronised
var app = React.renderToString(
AppFactory(data)
);
// In this point the react rendering was finished so we can flush the data and reset the stores
alt.flush();
В моем app.jsx
/**
*
*/
componentWillMount: function () {
// This beauty here is that componentWillMount is run on the server and the client so this is all we need to do. No need for other third-party isomorphic frameworks
alt.bootstrap(
JSON.stringify(this.props, null, 3)
);
}
Ответ 2
Взгляните на dispatchr и связанные с Yahoo библиотеки.
Большинство реализаций потока не работают в node.js, потому что они используют одноэлементные хранилища, диспетчеры и действия, и не имеют понятия "мы закончили", что необходимо знать, когда визуализировать html и отвечать к запросу.
Библиотеки Yahoo, такие как fetchr и router, обойти это ограничение node, используя очень чистую форму инъекции зависимостей (без функций синтаксического анализа для имен аргументов или чего-либо подобного).
Вместо этого вы определяете такие функции api, как это в services/todo.js:
create: function (req, resource, params, body, config, callback) {
И действия, подобные этому в actions/createTodo.js:
module.exports = function (context, payload, done) {
var todoStore = context.getStore(TodoStore);
...
context.dispatch('CREATE_TODO_START', newTodo);
...
context.service.create('todo', newTodo, {}, function (err, todo) {
Последняя строка косвенно вызывает функцию create в сервисах /todo.js. В этом случае косвенно может означать:
- на сервере:
- fetchr заполняет дополнительные аргументы, когда вы находитесь на сервере
- Затем он вызывает ваш обратный вызов
- на стороне клиента:
- клиент fetchr делает http-запрос
- fetchr на сервере перехватывает его
- он вызывает функцию сервиса с правильными аргументами
- он отправляет ответ обратно клиенту fetchr
- клиентская сторона fetchr обрабатывает вызов вашего обратного вызова
Это только верхушка айсберга. Это очень сложная группа модулей, которые работают вместе, чтобы решить сложную проблему и обеспечить полезную api. Изоморфизм по своей сути усложняется в реальных случаях использования. Вот почему многие реализации потоков не поддерживают рендеринг на стороне сервера.
Вы также можете посмотреть не используя флюс. Это не имеет смысла для всех приложений и часто просто мешает. Чаще всего вам это нужно только для нескольких частей приложения, если они есть. В программировании нет серебряных пуль!
Ответ 3
FakeRainBrigand правильно, что самая большая проблема с потоком на стороне сервера - это синглтоны. Flummox исправляет эту проблему, не используя синглтоны, и позволяет вам инкапсулировать всю вашу настройку Flux в один класс многоразового использования. Затем вы просто создаете новый экземпляр для каждого запроса. В сочетании с решением маршрутизации, таким как React Router, вы можете делать полностью изоморфные приложения.
Даже если вы не хотите использовать Flummox, источник легко получить, и вы можете использовать его в качестве руководства, чтобы взломать что-то самостоятельно:
https://github.com/acdlite/flummox
Ответ 4
Проблема в том, что при поиске "Flux server rendering" вы сразу сталкиваетесь с этим вопросом и не упоминаете Redux, сделанное сообществом React.js rackt. Вы можете найти красиво описанную в документации Redux , почему важно рендеринг сервера, почему нам нужно отправлять начальное состояние в пределах HTML
на клиент (который где Flux становится недостаточным) и как это сделать.