這篇文章主要介紹了使用RxJS管理React應(yīng)用狀態(tài)的方法,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。

隨著前端應(yīng)用的復(fù)雜度越來越高,如何管理應(yīng)用的數(shù)據(jù)已經(jīng)是一個不可回避的問題。當(dāng)你面對的是業(yè)務(wù)場景復(fù)雜、需求變動頻繁、各種應(yīng)用數(shù)據(jù)互相關(guān)聯(lián)依賴的大型前端應(yīng)用時,你會如何去管理應(yīng)用的狀態(tài)數(shù)據(jù)呢?
我們認(rèn)為應(yīng)用的數(shù)據(jù)大體上可以分為四類:
RxJS天生就適合編寫異步和基于事件的程序,那么狀態(tài)數(shù)據(jù)用什么去管理呢?還是用RxJS嗎? 合不合適呢?
我們?nèi)フ{(diào)研和學(xué)習(xí)了前端社區(qū)已有的優(yōu)秀的狀態(tài)管理解決方案,也從一些大牛分享的關(guān)于用RxJS設(shè)計數(shù)據(jù)層的構(gòu)想和實踐中得到了啟發(fā):
RxJS完全可以實現(xiàn)諸如Redux,Mobx等管理狀態(tài)數(shù)據(jù)的功能。observable來表達(dá),則可以借助RxJS基于序列且可響應(yīng)的的特性,以流的方式自由地拼接和組合各種類型的數(shù)據(jù),能夠更優(yōu)雅更高效地抽象出可復(fù)用可擴(kuò)展的業(yè)務(wù)模型。出于以上兩點原因,最終決定基于RxJS來設(shè)計一套管理應(yīng)用的狀態(tài)的解決方案。
原理介紹
對于狀態(tài)的定義,通常認(rèn)為狀態(tài)需要滿足以下3個條件:
event或者action對值進(jìn)行轉(zhuǎn)換,從而得到新的值。那么,RxJS適合用來管理狀態(tài)數(shù)據(jù)嗎?答案是肯定的!
首先,因為Observable本身就是多個值的推送集合,所以第一個條件是滿足的!
其次,我們可以實現(xiàn)一個使用dispatch action模式來推送數(shù)據(jù)的observable來滿足第二個條件!
眾所周知,RxJS中的observable可以分為兩種類型:
cold observable: 推送值的生產(chǎn)者(producer)來自observable內(nèi)部。
observable創(chuàng)建時被定義下來,不可改變。producer與觀察者(observer) 是一對一的關(guān)系,即是單播的。observer訂閱時,producer都會把預(yù)先定義好的若干個值依次推送給observer。hot observable: 推送值的producer來自observable外部。
producer與observer是一對多的關(guān)系,即是多播的。observer訂閱時,會將observer注冊到觀察者列表中,類似于其他庫或語言中的addListener的工作方式。producer被觸發(fā)或執(zhí)行時,會將值同時推送給所有的observer;也就是說,所有的observer共享了hot observable推送的值。RxJS提供的BehaviorSubject就是一種特殊的hot observable,它向外暴露了推送數(shù)據(jù)的接口next函數(shù);并且有“當(dāng)前值”的概念,它保存了發(fā)送給observer的最新值,當(dāng)有新的觀察者訂閱時,會立即從BehaviorSubject那接收到“當(dāng)前值”。
那么這說明使用BehaviorSubject來更新狀態(tài)并保存狀態(tài)的當(dāng)前值是可行的,第三個條件也滿足了。
簡單實現(xiàn)
請看以下的代碼:
import { BehaviorSubject } from 'rxjs';
// 數(shù)據(jù)推送的生產(chǎn)者
class StateMachine {
constructor(subject, value) {
this.subject = subject;
this.value = value;
}
producer(action) {
let oldValue = this.value;
let newValue;
switch (action.type) {
case 'plus':
newValue = ++oldValue;
this.value = newValue;
this.subject.next(newValue);
break;
case 'toDouble':
newValue = oldValue * 2;
this.value = newValue;
this.subject.next(newValue);
break;
}
}
}
const value = 1; // 狀態(tài)的初始值
const count$ = new BehaviorSubject(value);
const stateMachine = new StateMachine(count$, value);
// 派遣action
function dispatch(action) {
stateMachine.producer(action);
}
count$.subscribe(val => {
console.log(val);
});
setTimeout(() => {
dispatch({
type: "plus"
});
}, 1000);
setTimeout(() => {
dispatch({
type: "toDouble"
});
}, 2000);執(zhí)行代碼控制臺會打印出三個值:
Console 1 2 4
上面的代碼簡單實現(xiàn)了一個簡單管理狀態(tài)的例子:
plus之后的狀態(tài)值: 2toDouble之后的狀態(tài)值: 4實現(xiàn)方法挺簡單的,就是使用BehaviorSubject來表達(dá)狀態(tài)的當(dāng)前值:
dispatch函數(shù)使producer函數(shù)執(zhí)行producer函數(shù)在內(nèi)部調(diào)用了BehaviorSubject的next函數(shù),推送了新數(shù)據(jù),BehaviorSubject的當(dāng)前值更新了,也就是狀態(tài)更新了。不過寫起來略微繁瑣,我們對其進(jìn)行了封裝,優(yōu)化后寫法見下文。
我們自定義了一個操作符state用來創(chuàng)建一個能夠通過dispatch action模式推送新數(shù)據(jù)的BehaviorSubject,我們稱她為stateObservable。
const count$ = state({
// 狀態(tài)的唯一標(biāo)識名稱
name: "count",
// 狀態(tài)的默認(rèn)值
defaultValue: 1,
// 數(shù)據(jù)推送的生產(chǎn)者函數(shù)
producer(next, value, action) {
switch (action.type) {
case "plus":
next(value + 1);
break;
case "toDouble":
next(value * 2);
break;
}
}
});在你想要的任意位置使用函數(shù)dispatch派遣action即可更新狀態(tài)!
dispatch("count", {
type: "plus"
})RxJS的一大優(yōu)勢就在于能夠統(tǒng)一同步和異步,使用observable處理數(shù)據(jù)你不需要關(guān)注同步還是異步。
下面的例子我們使用操作符from將promise轉(zhuǎn)換為observable。
observable作為狀態(tài)的初始值(首次推送數(shù)據(jù))const todos$ = state({
name: "todos",
// `observable`推送的數(shù)據(jù)將作為狀態(tài)的初始值
initial: from(getAsyncData())
//...
});producer推送observableconst todos$ = state({
name: "todos",
defaultValue: []
// 數(shù)據(jù)推送的生產(chǎn)者函數(shù)
producer(next, value, action) {
switch (action.type) {
case "getAsyncData":
next(
from(getAsyncData())
);
break;
}
}
});執(zhí)行getAsyncData之后,from(getAsyncData())的推送數(shù)據(jù)將成為狀態(tài)的最新值。
由于狀態(tài)todos$是一個observable,所以可以很自然地使用RxJS操作符轉(zhuǎn)換得到另一個新的observable。并且這個observable的推送來自todos$;也就是說只要todos$推送新數(shù)據(jù),它也會推送;效果類似于Vue的計算屬性。
// 未完成任務(wù)數(shù)量
const undoneCount$ = todos$.pipe(
map(todos => {
let _conut = 0;
todos.forEach(item => {
if (!item.check) ++_conut;
});
return _conut;
})
);我們可能會在組件的生命周期內(nèi)訂閱observable得到數(shù)據(jù)渲染視圖。
class Todos extends React.Component {
componentWillMount() {
todos$.subscribe(data => {
this.setState({
todos: data
});
});
}
}我們可以再優(yōu)化下,利用高階組件封裝一個裝飾器函數(shù)@subscription,顧名思義,就是為React組件訂閱observable以響應(yīng)推送數(shù)據(jù)的變化;它會將observable推送的數(shù)據(jù)轉(zhuǎn)換為React組件的props。
@subscription({
todos: todos$
})
class TodoList extends React.Component {
render() {
return (
<p className="todolist">
<h2 className="header">任務(wù)列表</h2>
{this.props.todos.map((item, n) => {
return <TodoItem item={item} key={item.desc} />;
})}
</p>
);
}
}使用RxJS越久,越令人受益匪淺。
observable序列提供了較高層次的抽象,并且是觀察者模式,可以盡可能地減少各組件各模塊之間的耦合度,大大減輕了定位BUG和重構(gòu)的負(fù)擔(dān)。observable序列來編寫代碼的,所以遇到復(fù)雜的業(yè)務(wù)場景,總能按照一定的順序使用observable描述出來,代碼的可讀性很強(qiáng)。并且當(dāng)需求變動時,我可能只需要調(diào)整下observable的順序,或者加個操作符就行了。再也不必因為一個復(fù)雜的業(yè)務(wù)流程改動了,需要去改好幾個地方的代碼(而且還容易改出BUG,笑~)。所以,以上基于RxJS的狀態(tài)管理方案,對我們來說是一個必需品,因為我們項目中大量使用了RxJS,如果狀態(tài)數(shù)據(jù)也是observable,對我們抽象可復(fù)用可擴(kuò)展的業(yè)務(wù)模型是一個非常大的助力。當(dāng)然了,如果你的項目中沒有使用RxJS,也許Redux和Mobx是更合適的選擇。
這套基于RxJS的狀態(tài)管理方案,我們已經(jīng)用于開發(fā)公司的商用項目,反饋還不錯。所以我們決定把這套方案整理成一個js lib,取名為:Floway,并在github上開源:
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享使用RxJS管理React應(yīng)用狀態(tài)的方法內(nèi)容對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,遇到問題就找創(chuàng)新互聯(lián),詳細(xì)的解決方法等著你來學(xué)習(xí)!
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
網(wǎng)站名稱:使用RxJS管理React應(yīng)用狀態(tài)的方法-創(chuàng)新互聯(lián)
URL地址:http://www.chinadenli.net/article36/dgsssg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、App開發(fā)、全網(wǎng)營銷推廣、網(wǎng)站設(shè)計公司、定制開發(fā)、網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容