Reflux是根據React的flux建立的單向數據流類庫。
Reflux的單向數據流模式主要由actions和stores組成。例如,當組件list新增item時,會調用actions的某個方法(如addItem(data)),並將新的數據當參數傳遞進去,經過事件機制,數據會傳遞到stroes中,stores能夠向服務器發起請求,並更新數據數據庫。數據更新成功後,仍是經過事件機制傳遞的組件list當中,並更新ui。整個過程的對接是經過事件驅動的。就像這樣:react
╔═════════╗ ╔════════╗ ╔═════════════════╗ ║ Actions ║──────>║ Stores ║──────>║ View Components ║ ╚═════════╝ ╚════════╝ ╚═════════════════╝ ^ │ └──────────────────────────────────────┘
代碼看起來像這樣的:git
var TodoActions = Reflux.createActions([ 'addItem' ]); var TodoStore = Reflux.createStore({ items: [1, 2], listenables: [TodoActions], onAddItem: function (model) { $.post('/server/add', {data: model}, function (data) { this.items.unshift(data); this.trigger(this.items); }); } }); var TodoComponent = React.createClass({ mixins: [Reflux.listenTo(TodoStore, 'onStatusChange')], getInitialState: function () { return {list: []}; }, onStatusChange: function () { this.setState({list: TodoStore.items}); }, render: function () { return ( <div> {this.state.list.map(function (item) { return <p>{item}</p> })} </div> ) } }); React.render(<TodoComponent />, document.getElementById('container'));
var statusUpdate = Reflux.createAction(options);
返回值是一個函數,調用這個函數就會觸發相應的事件,在store中監聽這個函數,並做相應的處理github
var addItem = Reflux.createAction(); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(addItem, 'addItem'); }, addItem: function (model) { console.log(model); } }); addItem({name: 'xxx'});
var TodoActions = Reflux.createActions([ 'addItem', 'deleteItem' ]);
store監聽actions的行爲:數據庫
var TodoActions = Reflux.createActions([ 'addItem', 'deleteItem' ]); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(TodoActions.addItem, 'addItem'); this.listenTo(TodoActions.deleteItem, 'deleteItem'); }, addItem: function (model) { console.log(model) }, deleteItem:function(model){ console.log(model); } }); TodoActions.addItem({name:'xxx'}); TodoActions.deleteItem({name:'yyy'});
真實的應用場景中,幾乎全部的操做都會向後端請求,而這些操做都是異步的,Reflux也提供了相應的Promise接口後端
var getAll = Reflux.createAction({asyncResult:true});
例如獲取所有數據:promise
var getAll = Reflux.createAction({asyncResult: true}); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(getAll, 'getAll'); }, getAll: function (model) { $.get('/all', function (data) { if (data) { getAll.completed(data); } else { getAll.failed(data); } }); } }); getAll({name: 'xxx'}) .then(function (data) { console.log(data); }) .catch(function (err) { throw err; });
Reflux爲每一個action都提供了兩個hook方法服務器
情景一:異步
var addItem = Reflux.createAction({ preEmit: function (params) { console.log('preEmit:' + params); }, shouldEmit: function (params) { console.log('shouldEmit:' + params); } }); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(addItem, 'addItem'); }, addItem: function (params) { console.log('addItem:' + params); } }); addItem('xxx'); 控制檯打印 $ preEmit:xxx $ shouldEmit:xxx
情景二:async
var addItem = Reflux.createAction({ preEmit: function (params) { console.log('preEmit:' + params); return 324; }, shouldEmit: function (params) { console.log('shouldEmit:' + params); return true; } }); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(addItem, 'addItem'); }, addItem: function (params) { console.log('addItem:' + params); } }); addItem('xxx'); 控制檯打印 $ preEmit:xxx $ shouldEmit:324 $ addItem:324
注意幾個返回值和參數的關係函數
當須要給全部的action添加公用方法時,能夠這麼幹:
Reflux.ActionMethods.print = function (str) { console.log(str); }; var addItem = Reflux.createAction(); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(addItem, 'addItem'); }, addItem: function (params) { console.log('addItem:' + params); } }); addItem.print('xxx');
直接調用addItem()其實是調用trigger或者triggerAsync或者triggerPromise,它們區別在於
var addItem = Reflux.createAction(); addItem(); #默認調用triggerAsync,至關於addItem.triggerAsync() var addItem = Reflux.createAction({sync:true});addItem(); #默認調用trigger,至關於addItem.trigger() var addItem = Reflux.createAction({asyncResult:true});addItem();#默認調用triggerPromise,至關於addItem.triggerPromise()
trigger和triggerAsync區別在於:
triggerAsync = setTimeout(function () { trigger() }, 0);
trigger和triggerPromise區別在於,triggerPromise的返回值是promise
Store能夠響應Action的行爲,並同服務器交互。
在init方法中添加監聽處理
var addItem = Reflux.createAction(); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(addItem, 'addItem'); }, addItem: function (model) { console.log(model); } }); addItem({name: 'xxx'});
var TodoActions = Reflux.createActions([ 'addItem', 'deleteItem' ]); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(TodoActions.addItem, 'addItem'); this.listenTo(TodoActions.deleteItem, 'deleteItem'); }, addItem: function (model) { console.log(model); }, deleteItem: function (model) { console.log(model); } }); TodoActions.addItem({name: 'xxx'}); TodoActions.deleteItem({name: 'yyy'});
兩個action的時候在init裏寫了兩遍監聽處理方法,若是有十個甚至多個的話,寫起來就像這樣的:
var TodoActions = Reflux.createActions([ 'item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7', 'item8', 'item9', 'item10' ]); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(TodoActions.item1, 'item1'); this.listenTo(TodoActions.item2, 'item2'); this.listenTo(TodoActions.item3, 'item3'); this.listenTo(TodoActions.item4, 'item4'); this.listenTo(TodoActions.item5, 'item5'); this.listenTo(TodoActions.item6, 'item6'); this.listenTo(TodoActions.item7, 'item7'); this.listenTo(TodoActions.item8, 'item8'); this.listenTo(TodoActions.item9, 'item9'); this.listenTo(TodoActions.item10, 'item10'); }, item1: function (model) { console.log(model); }, item2: function (model) { console.log(model); } }); TodoActions.item1({name: 'xxx'}); TodoActions.item2({name: 'yyy'});
還好Reflux給咱們提供了listenToMany方法,避免重複勞動:
var TodoActions = Reflux.createActions([ 'item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7', 'item8', 'item9', 'item10' ]); var TodoStore = Reflux.createStore({ init: function () { this.listenToMany(TodoActions); }, onItem1: function (model) { console.log(model); }, onItem2: function (model) { console.log(model); } }); TodoActions.item1({name: 'xxx'}); TodoActions.item2({name: 'yyy'});
處理方法只需讓action的標識首字母大寫並加上on就能夠了。
標識若是首字母大寫就會識別不了,例如將上面的item1改爲Itme1。這坑爹的!
var TodoActions = Reflux.createActions([ 'item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7', 'item8', 'item9', 'item10' ]); var TodoStore = Reflux.createStore({ listenables: [TodoActions], onItem1: function (model) { console.log(model); }, onItem2: function (model) { console.log(model); } }); TodoActions.item1({name: 'xxx'}); TodoActions.item2({name: 'yyy'});
通常咱們寫真實應用的時候都應該採用這種寫法!!!
拓展Store的公用方法有兩種方式。
Reflux.StoreMethods.print = function (str) { console.log(str); }; var addItem = Reflux.createAction(); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(addItem, 'addItem'); }, addItem: function (model) { console.log(model); } }); TodoStore.print('rrr');
var Mixins = { print: function (str) { console.log(str); } } var addItem = Reflux.createAction(); var TodoStore = Reflux.createStore({ mixins: [Mixins], init: function () { this.listenTo(addItem, 'addItem'); }, addItem: function (model) { console.log(model); } }); TodoStore.print('rrr');
前面說了,Action、Store和組件這三者是經過事件機制響應變化的,構建組件的時候首先須要監聽Store的狀態。
先定義Action和Store
var TodoActions = Reflux.createActions([ 'getAll' ]); var TodoStore = Reflux.createStore({ items: [1,2,3], listenables: [TodoActions], onGetAll: function () { this.trigger(this.items); } });
var TodoComponent = React.createClass({ getInitialState: function () { return {list: []}; }, onStatusChange: function (list) { this.setState({list: list}); }, componentDidMount: function () { this.unsubscribe = TodoStore.listen(this.onStatusChange); TodoActions.getAll(); }, componentWillUnmount: function () { this.unsubscribe(); }, render: function () { return ( <div> {this.state.list.map(function (item) { return <p>{item}</p> })} </div> ) } }); React.render(<TodoComponent />, document.getElementById('container'));
這裏有兩點須要注意:
var TodoComponent = React.createClass({ mixins: [Reflux.ListenerMixin], getInitialState: function () { return {list: []}; }, onStatusChange: function (list) { this.setState({list: list}); }, componentDidMount: function () { this.unsubscribe = TodoStore.listen(this.onStatusChange); TodoActions.getAll(); }, render: function () { return ( <div> {this.state.list.map(function (item) { return <p>{item}</p> })} </div> ) } }); React.render(<TodoComponent />, document.getElementById('container'));
var TodoComponent = React.createClass({ mixins: [Reflux.listenTo(TodoStore,'onStatusChange')], getInitialState: function () { return {list: []}; }, onStatusChange: function (list) { this.setState({list: list}); }, componentDidMount: function () { TodoActions.getAll(); }, render: function () { return ( <div> {this.state.list.map(function (item) { return <p>{item}</p> })} </div> ) } }); React.render(<TodoComponent />, document.getElementById('container'));
var TodoComponent = React.createClass({ mixins: [Reflux.connect(TodoStore,'list')], getInitialState: function () { return {list: []}; }, componentDidMount: function () { TodoActions.getAll(); }, render: function () { return ( <div> {this.state.list.map(function (item) { return <p>{item}</p> })} </div> ) } }); React.render(<TodoComponent />, document.getElementById('container'));
數據會自動更新到state的list當中。
var TodoComponent = React.createClass({ mixins: [Reflux.connectFilter(TodoStore, 'list', function (list) { return list.filter(function (item) { return item > 1; }); })], getInitialState: function () { return {list: []}; }, componentDidMount: function () { TodoActions.getAll(); }, render: function () { return ( <div> {this.state.list.map(function (item) { return <p>{item}</p> })} </div> ) } }); React.render(<TodoComponent />, document.getElementById('container'));
對數據加了一層過濾器。
以上便Component同Store交互的內容,你們能夠根據實際狀況選擇不一樣的寫法。
我這人喜歡拿代碼來表述思想。
var TodoActions = Reflux.createActions([ 'getAll', 'addItem', 'deleteItem', 'updateItem' ]); var TodoStore = Reflux.createStore({ items: [1, 2, 3], listenables: [TodoActions], onGetAll: function () { $.get('/all', function (data) { this.items = data; this.trigger(this.items); }.bind(this)); }, onAddItem: function (model) { $.post('/add', model, function (data) { this.items.unshift(data); this.trigger(this.items); }.bind(this)); }, onDeleteItem: function (model, index) { $.post('/delete', model, function (data) { this.items.splice(index, 1); this.trigger(this.items); }.bind(this)); }, onUpdateItem: function (model, index) { $.post('/update', model, function (data) { this.items[index] = data; this.trigger(this.items); }.bind(this)); } }); var TodoComponent = React.createClass({ mixins: [Reflux.connect(TodoStore, 'list')], getInitialState: function () { return {list: []}; }, componentDidMount: function () { TodoActions.getAll(); }, render: function () { return ( <div> {this.state.list.map(function(item){ return <TodoItem data={item}/> })} </div> ) } }); var TodoItem = React.createClass({ componentDidMount: function () { TodoActions.getAll(); }, handleAdd: function (model) { TodoActions.addItem(model); }, handleDelete: function (model,index) { TodoActions.deleteItem(model,index); }, handleUpdate: function (model) { TodoActions.updateItem(model); }, render: function () { var item=this.props.data; return ( <div> <p>{item.name}</p> <p>{item.email}</p> <p>/*操做按鈕*/</p> </div> ) } }); React.render(<TodoComponent />, document.getElementById('container'));
實際狀況遠比這複雜,只是提供一個思路供你們參考。