摘要:概念是根據(jù)的創(chuàng)建的單向數(shù)據(jù)流類庫。的單向數(shù)據(jù)流模式主要由和組成。數(shù)據(jù)更新成功后,還是通過事件機制傳遞的組件當(dāng)中,并更新。整個過程的對接是通過事件驅(qū)動的。標(biāo)識如果首字母大寫就會識別不了,例如將上面的改成。
概念
Reflux是根據(jù)React的flux創(chuàng)建的單向數(shù)據(jù)流類庫。
Reflux的單向數(shù)據(jù)流模式主要由actions和stores組成。例如,當(dāng)組件list新增item時,會調(diào)用actions的某個方法(如addItem(data)),并將新的數(shù)據(jù)當(dāng)參數(shù)傳遞進去,通過事件機制,數(shù)據(jù)會傳遞到stroes中,stores可以向服務(wù)器發(fā)起請求,并更新數(shù)據(jù)數(shù)據(jù)庫。數(shù)據(jù)更新成功后,還是通過事件機制傳遞的組件list當(dāng)中,并更新ui。整個過程的對接是通過事件驅(qū)動的。就像這樣:
╔═════════╗ ╔════════╗ ╔═════════════════╗ ║ Actions ║──────>║ Stores ║──────>║ View Components ║ ╚═════════╝ ╚════════╝ ╚═════════════════╝ ^ │ └──────────────────────────────────────┘
代碼看起來像這樣的:
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 (同React Flux比較 相同點{this.state.list.map(function (item) { return) } }); React.render({item}
})}, document.getElementById("container"));
有actions
有stores
單向數(shù)據(jù)流
不同點通過內(nèi)部拓展actions的行為,移除了單例的dispatcher
stores可以監(jiān)聽actions的行為,無需進行冗雜的switch判斷
stores可以相互監(jiān)聽,可以進行進一步的數(shù)據(jù)聚合操作,類似于,map/reduce
waitFor被連續(xù)和平行的數(shù)據(jù)流所替代
創(chuàng)建Actionvar statusUpdate = Reflux.createAction(options);
返回值是一個函數(shù),調(diào)用這個函數(shù)就會觸發(fā)相應(yīng)的事件,在store中監(jiān)聽這個函數(shù),并作相應(yīng)的處理
var addItem = Reflux.createAction(); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(addItem, "addItem"); }, addItem: function (model) { console.log(model); } }); addItem({name: "xxx"});創(chuàng)建多個Action
var TodoActions = Reflux.createActions([ "addItem", "deleteItem" ]);
store監(jiān)聽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"});異步Action
真實的應(yīng)用場景中,幾乎所有的操作都會向后端請求,而這些操作都是異步的,Reflux也提供了相應(yīng)的Promise接口
var getAll = Reflux.createAction({asyncResult:true});
例如獲取全部數(shù)據(jù):
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; });Action hooks
Reflux為每個action都提供了兩個hook方法
preEmit(params),action emit之前調(diào)用,參數(shù)是action傳遞過來的,返回值會傳遞給shouldEmit
shouldEmit(params) action emit之前調(diào)用,參數(shù)默認(rèn)是action傳遞,如果preEmit有返回值,則是preEmit返回值,返回值決定是否emit
情景一:
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
情景二:
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 Methods注意幾個返回值和參數(shù)的關(guān)系
當(dāng)需要給所有的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");trigger、triggerAsync和triggerPromise
直接調(diào)用addItem()實際上是調(diào)用trigger或者triggerAsync或者triggerPromise,它們區(qū)別在于
var addItem = Reflux.createAction(); addItem(); #默認(rèn)調(diào)用triggerAsync,相當(dāng)于addItem.triggerAsync() var addItem = Reflux.createAction({sync:true});addItem(); #默認(rèn)調(diào)用trigger,相當(dāng)于addItem.trigger() var addItem = Reflux.createAction({asyncResult:true});addItem();#默認(rèn)調(diào)用triggerPromise,相當(dāng)于addItem.triggerPromise()
trigger和triggerAsync區(qū)別在于:
triggerAsync = setTimeout(function () { trigger() }, 0);
trigger和triggerPromise區(qū)別在于,triggerPromise的返回值是promise
創(chuàng)建StoreStore可以響應(yīng)Action的行為,并同服務(wù)器交互。
監(jiān)聽單個Action在init方法中添加監(jiān)聽處理
var addItem = Reflux.createAction(); var TodoStore = Reflux.createStore({ init: function () { this.listenTo(addItem, "addItem"); }, addItem: function (model) { console.log(model); } }); addItem({name: "xxx"});監(jiān)聽多個Action 作死寫法
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里寫了兩遍監(jiān)聽處理方法,如果有十個甚至多個的話,寫起來就像這樣的:
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"});listenToMany
還好Reflux給我們提供了listenToMany方法,避免重復(fù)勞動:
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的標(biāo)識首字母大寫并加上on就可以了。
listenables標(biāo)識如果首字母大寫就會識別不了,例如將上面的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"});
一般我們寫真實應(yīng)用的時候都應(yīng)該采用這種寫法?。?!
Store Methods拓展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");同組件結(jié)合
前面說了,Action、Store和組件這三者是通過事件機制響應(yīng)變化的,構(gòu)建組件的時候首先需要監(jiān)聽Store的狀態(tài)。
先定義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 ({this.state.list.map(function (item) { return) } }); React.render({item}
})}, document.getElementById("container"));
這里有兩點需要注意:
當(dāng)組件的生命周期結(jié)束時需要解除對Store的監(jiān)聽
當(dāng)Store調(diào)用trigger時,才會執(zhí)行onStatusChange函數(shù),所以每次Store更新時,需要手動調(diào)用trigger函數(shù)
Mixinsvar 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 (Reflux.listenTo{this.state.list.map(function (item) { return) } }); React.render({item}
})}, 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 (Reflux.connect{this.state.list.map(function (item) { return) } }); React.render({item}
})}, document.getElementById("container"));
var TodoComponent = React.createClass({ mixins: [Reflux.connect(TodoStore,"list")], getInitialState: function () { return {list: []}; }, componentDidMount: function () { TodoActions.getAll(); }, render: function () { return ({this.state.list.map(function (item) { return) } }); React.render({item}
})}, document.getElementById("container"));
數(shù)據(jù)會自動更新到state的list當(dāng)中。
Reflux.connectFiltervar 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 ({this.state.list.map(function (item) { return) } }); React.render({item}
})}, document.getElementById("container"));
對數(shù)據(jù)加了一層過濾器。
小結(jié)以上便Component同Store交互的內(nèi)容,大家可以根據(jù)實際情況選擇不同的寫法。
我這人喜歡拿代碼來表述思想。
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 ({this.state.list.map(function(item){ return) } }); 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 (})} ) } }); React.render({item.name}
{item.email}
/*操作按鈕*/
, document.getElementById("container"));
實際情況遠(yuǎn)比這復(fù)雜,只是提供一個思路供大家參考。
代碼鏈接github
參考Reflux
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/92330.html
摘要:是分發(fā)器,是數(shù)據(jù)與邏輯處理器,會在注冊針對各個命令字的響應(yīng)回調(diào)函數(shù)。當(dāng)按如下方式觸發(fā)回調(diào)時,回調(diào)函數(shù)具備事件的特性。 本系列博文從 Shadow Widget 作者的視角,解釋該框架的設(shè)計要點。本篇解釋 Shadow Widget 在 MVC、MVVM、Flux 框架之間如何做選擇。 showImg(https://segmentfault.com/img/bVOODj?w=380&h...
摘要:當(dāng)使用對象時,在生命周期中運行,此時環(huán)境下已經(jīng)完成了。并不會隨著的更新而改變,因此在使用時一定要注意是否有。但是使用會跳過的過程,會觸發(fā)子組件的所有方法包括從而造成性能的浪費。因此為了組件更加清晰高效,應(yīng)該避免使用。我推薦使用來管理。 兩種架構(gòu) 現(xiàn)在使用React的開發(fā)模式主要有兩種——freeMarker+React以及純靜態(tài)React頁面開發(fā)。本文著重介紹純靜態(tài)React頁面的開...
摘要:上例的功能塊定義了如下節(jié)點樹入口節(jié)點是面板,結(jié)合該節(jié)點的函數(shù)書寫特點,我們接著介紹最佳實踐如何處理功能塊之內(nèi)的編程。 本文介紹 React + Shadow Widget 應(yīng)用于通用 GUI 開發(fā)的最佳實踐,只聚焦于典型場景下最優(yōu)開發(fā)方法。分上、下兩篇講解,上篇概述最佳實踐,介紹功能塊劃分。 showImg(https://segmentfault.com/img/bVWu3d?w=6...
摘要:的關(guān)鍵構(gòu)成梳理了一下,需要配合的庫去使用,是因為要解決通信問題。還有各個事件之間,有可能存在依賴關(guān)系,事件后,也觸發(fā)。相比于傳統(tǒng)的事件系統(tǒng),融入了不少的思想。中,將會是最大的門檻之一。 從學(xué)習(xí)React到現(xiàn)在的一點感受 我覺得應(yīng)該有不少同學(xué)和我一樣,上來學(xué)React,覺得甚是驚艷,看著看著,發(fā)現(xiàn)facebook 安利了一個flux,圖畫的巨復(fù)雜,然后各種例子都有用這個東西,沒辦法,硬著...
閱讀 1150·2021-11-25 09:43
閱讀 1583·2021-10-25 09:47
閱讀 2478·2019-08-30 13:46
閱讀 764·2019-08-29 13:45
閱讀 1292·2019-08-26 13:29
閱讀 3000·2019-08-23 15:30
閱讀 1113·2019-08-23 14:17
閱讀 1336·2019-08-23 13:43