React + Flux: получение начального состояния в хранилище
Недавно мы перешли на React + Flux из Angular, чтобы построить довольно сложное бизнес-приложение.
Принимая подход к тому, что один компонент контейнера, который передает все состояние в качестве свойств вниз по дереву компонентов, не является практическим способом разработки приложения для нас, так как приложение использует большие страницы-подобные модалы. Достаточное состояние передается модально для их загрузки своих данных в свои магазины.
У меня есть проблема: мне нужно получить начальное состояние (переданное как реквизит) в хранилище модальных компонентов. В этот пост хорошие парни в Facebook говорят, что это нормально использовать реквизиты для начального состояния, когда синхронизация не является целью.
Вот как я получаю начальное состояние в моем магазине в настоящее время:
var ABC = React.createClass({
...
getInitialState: function() {
return ABCStore.getInitialABCState(this.props.initialA);
},
...
var ABCStore = Reflux.createStore({
...
init: function() {
_state = {
a: null,
b: 'B init',
c: 'C init'
};
},
getInitialABCState: function(initialA) {
_state.a = initialA;
return _state;
},
getABCState: function() {
return _state;
}
...
Я не уверен, что лучше всего сделать это, или это анти-шаблон Flux?
Ответы
Ответ 1
Мне кажется неправильным, что вы используете getInitialState()
для изменения состояния своего магазина. Вы должны хотя бы сделать это в componentWillMount
.
Я бы вызвал действие в componentWillMount
и обработчик хранилища обновил внутреннее состояние хранилища (это всегда должно происходить в потоке). Затем ваш обработчик изменения компонента для хранилища может использовать все данные, которые вы в настоящее время вызываете в своем "начальном состоянии"
Ответ 2
Reflux.listenTo
делает это, когда вы предоставляете третий аргумент и Reflux.connect
mixin factory (который использует Reflux.listenTo
под капотом ) обрабатывает это для вас автоматически. Вот пример:
var Actions = Reflux.createActions({"doIt"});
var Store = Reflux.createStore({
listenables: [Actions],
init: function() {
this.state = "I like to";
},
onDoIt: function() {
this.state = "Do it";
this.trigger(this.state);
},
getInitialState: function() {
return this.state;
}
});
var DoItButton = React.createClass({
mixins: [Reflux.connect(Store, "label")],
onClick: function() {
Actions.doIt();
},
render: function() {
return (<div onClick={this.onClick}>{this.state.label}</div>);
}
});
Ответ 3
Как и другие плакаты, самое лучшее, что нужно сделать, это запустить действие в componentWillMount
. В ES6 это обычно делается с помощью constructor
.
Ниже приведен пример того, как это сделать с ES6:
(обратите внимание, что AuthorActions.initAuthors()
зависит от реализации, это просто пример, который может получить исходное состояние из базы данных. Самое главное, это действие должно отправить полезную нагрузку с начальным состоянием диспетчеру)
var _authors = [];
var AuthorStoreInstance;
class AuthorStore extends EventEmitter {
constructor(props) {
super(props);
}
init() {
AuthorActions.initAuthors();
this.emitChange();
}
addChangeListener(cb) {
this.on(CHANGE_EVENT, cb);
}
removeChangeListener(cb) {
this.removeListener(CHANGE_EVENT, cb);
}
emitChange() {
this.emit(CHANGE_EVENT);
}
getAllAuthors() {
return _authors;
}
addAuthor(author) {
_authors.push(author);
this.emitChange();
}
setAuthors(authors) {
_authors = authors;
}
};
AuthorStoreInstance = new AuthorStore();
Dispatcher.register((action) => {
switch(action.actionType) {
case ActionTypes.CREATE_AUTHOR:
AuthorStoreInstance.addAuthor(action.author);
break;
case ActionTypes.INITIALIZE:
AuthorStoreInstance.setAuthors(action.initialData.authors);
break;
default:
//do nothing
}
});
AuthorStoreInstance.init();
export default AuthorStoreInstance;
Обратите внимание, что функция init не является частью конструктора. Это связано с тем, что при построении authorStore обратный вызов для AuthorActions.initAuthors
не был зарегистрирован диспетчером.
Инициализация должна произойти после регистрации обратных вызовов в диспетчере.
edit: Для ясности initAuthors
может выглядеть примерно так:
initAuthors() {
var authors = AuthorAPI.getAllAuthors();
Dispatcher.dispatch({
actionType: ActionTypes.INITIALIZE,
initialData: {
authors: authors
}
});
}