2015-03-10 4 views
13

Мы недавно перешли на React + Flux из Angular, чтобы построить довольно сложное бизнес-приложение.React + Flux: получение начального состояния в магазине

Принимая во внимание, что один компонент контейнера, который передает все состояние в качестве свойств вниз по дереву компонентов, не является практическим способом разработки приложения для нас, поскольку приложение использует большие модальные страницы. Достаточное состояние передается модально для их загрузки своих данных в свои магазины.

У меня есть проблема: мне нужно получить начальное состояние (переданное как реквизит) в хранилище модального компонента. В this post хорошие ребята в 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

Он чувствует, как вы находитесь на крае антишаблона с этим магазином. Однако замечательная вещь о Flux - это скорее архитектурная концепция, чем просто компонент. Это означает, что вы можете создавать магазины несколькими способами и поддерживать их в духе Flux. В проекте, над которым я работал, мы использовали диспетчер из библиотеки Flux, а это означало, что хранилище не было инициализировано, как ваш пример.Магазин просто заселялся, когда нужны данные (действия от компонентов или маршрутизатора). Я не думаю, что ваш пример - плохая практика, но это открывает отличную дискуссию. – magnudae

+0

Да, я надеюсь заговорить об этом, потому что у меня тоже есть это чувство, но мне нужно больше конкретного материала :) –

ответ

12

Мне кажется неправильным, что вы используете getInitialState(), чтобы изменить состояние своего магазина. Вы должны хотя бы сделать это в componentWillMount.

Я бы вызвал действие в componentWillMount и обработчик хранилища обновил внутреннее состояние магазина (это всегда должно происходить в потоке). Тогда обработчик изменения вашего компонента для магазина может потреблять все данные, которые вы в настоящее время звоните «начальное состояние»

+0

Добавляя к вашему ответу, я предлагаю потратить несколько часов на изучение [приложения чата facebook] (https: // github .com/facebook/флюс/BLOB/Master/примеры/флюс-чат/JS /). Он охватывает почти все. –

+6

Похоже, что приложение для чата получает исходное состояние в 'getInitialState', в отличие от предложенного' componentWillMount'. – Ryan

4

Reflux.listenTo делает это, когда вы предоставите третий аргумент и Reflux.connect подмешать завод (который использует 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>); 
    } 
}); 
+0

Спасибо за ответ - я немного смущен. В вашем примере вы, кажется, не отправляете начальное состояние в магазин, а скорее получаете его из магазина? В моем примере мне нужно получить свойство 'initialA', предоставленное моему компоненту в мой магазин. Я что-то упускаю? –

+0

@MarkusCoetzee Так как же вы устанавливаете 'initialA' из компонента, а не из магазина? – Spoike

+0

Компонент получает это свойство (передается из родительского контейнера). Это свойство является частью исходного состояния компонента. Мой вопрос в том, что такое способ Flux для получения этого начального состояния в хранилище –

0

Как и другие плакаты уже говорил, самое лучшее, что нужно сделать, это вызвать действие в 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; 

Обратите внимание, как функция инициализации не является частью конструктора. Это связано с тем, что при создании authorStore обратный вызов для AuthorActions.initAuthors не был зарегистрирован диспетчером.

Инициализация должна произойти после регистрации обратных вызовов с диспетчером.

редактировать: Для ясности, initAuthors может выглядеть примерно так:

initAuthors() { 
    var authors = AuthorAPI.getAllAuthors(); 

    Dispatcher.dispatch({ 
     actionType: ActionTypes.INITIALIZE, 
     initialData: { 
      authors: authors 
     } 
    }); 
} 
Смежные вопросы