淺聊一下為什么能用RxJS取代Redux
RxJS 在現(xiàn)在的前端用比較少,但是 RxJS 作為響應(yīng)式和函數(shù)式編程的集大成者,似乎被前端開發(fā)者遺忘,可能是學(xué)習(xí)難度大,可能是有更加方便的解決方案。
不是因?yàn)?Redux 更具有性價(jià)比,而是 RxJS 可以打開更大的 JS 生態(tài)空間
下面我們先回顧一下 Redux 是如何運(yùn)作開始。
一、Redux 創(chuàng)建一個(gè) Store 做了哪些事情?
以上是一個(gè)簡(jiǎn)單的 Redux 的工作流。從 reducer 到視圖派發(fā)更新的整個(gè)流程
Redux 通常在單頁(yè)面應(yīng)用中,與React結(jié)合,他的基本使用流程。
- 定義 Reducer 函數(shù)
- 使用 createStore 函數(shù)傳入 Reducer 創(chuàng)建 store
- 訂閱函數(shù) store
- 派發(fā)類型更新數(shù)據(jù)。
以下是一個(gè)官網(wǎng)的例子:
import { createStore } from 'redux' function counterReducer(state = { value: 0 }, action) { switch (action.type) { case 'counter/incremented': return { value: state.value + 1 } case 'counter/decremented': return { value: state.value - 1 } default: return state } } let store = createStore(counterReducer) store.subscribe(() => console.log(store.getState())) store.dispatch({ type: 'counter/incremented' }) store.dispatch({ type: 'counter/decremented' })
創(chuàng)建一個(gè) Redux 其實(shí)也是需要訂閱(subscribe)數(shù)據(jù)。才能使用 dispatch 來(lái)派發(fā)行為到 reducer 里面。
二、React Redux 與 React 結(jié)合
React Redux 是 React 官方與 Redux 結(jié)合,方便在 React 組件中使用 Redux。提供了:
- Provider 組件
- 鉤子函數(shù)
- ...
2.1)Redux 的難點(diǎn)
初學(xué) Redux 難點(diǎn)就是熟練根據(jù)自己的業(yè)務(wù)完成此流程。
2.2)中心化
Redux 是將數(shù)據(jù)集中到一個(gè) store 庫(kù),集中化數(shù)據(jù)管理,在大型項(xiàng)目中,你可能不想講數(shù)據(jù)集中化,Redux 在新的版本 Redux Toolkit 有了分片等功能開始彌補(bǔ) Redux 的問(wèn)題。
初學(xué) Redux 其實(shí)還是有一定難度的,需要靈活使用 reducer 與 dispatch, 還需要 React 進(jìn)行結(jié)合。并且異步副作用在 Redux 中還不好處理。
2.3)異步任務(wù)處理
Redux 通常不能直接處理異步任務(wù),通常配合
- Redux-thunk
- Redux-saga
對(duì)異步任務(wù)進(jìn)行處理。基于以上我們知道了其實(shí) Redux 其實(shí)也具有自己優(yōu)點(diǎn)和缺點(diǎn)。
三、RxJS 為什么可以替代 Redux ?
3.1)React 作為視圖層
類似于 React 和 Vue 等框架,雖然組件具有自己的狀態(tài)管理,但是在復(fù)雜數(shù)據(jù)關(guān)系時(shí)力不從心。于是演化出了 Redux 等數(shù)據(jù)層管理庫(kù)。但是 RxJS 本身基于事件流,擁有強(qiáng)大的處理數(shù)據(jù)流能力。與視圖層集合便擁有了強(qiáng)大的數(shù)據(jù)處理能力。
3.2)Redux 作為數(shù)據(jù)層
通過(guò)以上的簡(jiǎn)介,可以理解 Redux 其實(shí)就是一個(gè) store 作為數(shù)據(jù)層而存在。它通常具有有以下一些操作:
- 存儲(chǔ)數(shù)據(jù)
- 取出數(shù)據(jù)
- 改變數(shù)據(jù)
- 異步處理
3.3) RxJS 作為數(shù)據(jù)層可以這樣做
RxJS 是一個(gè)函數(shù)式和響應(yīng)式的 JavaScript, 自帶響應(yīng)式數(shù)據(jù)能力。
普通的可觀察對(duì)象,只產(chǎn)生一個(gè)可觀察對(duì)象數(shù)據(jù)。也沒有緩存數(shù)據(jù)的能力。明顯不好,但是 RxJS 實(shí)現(xiàn)了 Subject 系列,其中 BehaviorSubject 能夠自帶初始值,并且也有緩存能力,能夠?qū)崿F(xiàn)跨組件的訂閱數(shù)據(jù)。
BehaviorSubject 是實(shí)現(xiàn) Store 中狀態(tài)管理的最佳選擇。
四、一個(gè)簡(jiǎn)單的 RxJS 實(shí)現(xiàn) Store
4.1)思考
我們要實(shí)現(xiàn)一個(gè) Store,我們基于 class 和 React 的 hooks 進(jìn)行設(shè)計(jì)。在 Store 需要考慮跨越組件和和跨越頁(yè)面的狀態(tài)管理設(shè)計(jì)。
- BehaviorSubject 行為主題具有函數(shù)數(shù)據(jù)和初始化能力,是作為狀態(tài)管理的最佳選擇
4.2)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 Store
import { BehaviorSubject, type SubjectLike } from "rxjs"; export class Store { state$; constructor() { this.state$ = new BehaviorSubject({counter: 10 }); } updateState(data: IState) { this.state$.next({ ...data }); } getState(): SubjectLike<any> { return this.state$; } unsubscribe() { this.state$.unsubscribe() } } export const store = new Store()
這個(gè) Store 也非常簡(jiǎn)單,在構(gòu)造函數(shù)中創(chuàng)建行為主題,然后再 getState 中獲取狀態(tài)主題,已經(jīng)在 updateState 中使用 next 方法更新主題,最后在 unsubscribe 中取消訂閱。
這里我們實(shí)例化一個(gè)全局 store, 然后輸出,方便在全局使用。
4.3)基于 Store 封裝 hooks 方便在 React 組件中使用
import { store } from './store' export function useStore() { const [data, setData] = useState<IState>({ counter: 0 }) useEffect(() => { store.getState().subscribe((v: any) => { setData(!v ? { counter: 0 } : v); }); return () => { store.unsubscribe() } }, []) const updateData = (data: IState) => { store.updateState({...data}) } return [data, updateData] }
注意: store 是設(shè)計(jì)考慮在全局使用的,意味著這里的 useStore 是具有跨越頁(yè)面和組件能力的。其中重要的方法 updateData 是通過(guò)在修改 Store 內(nèi)部的數(shù)據(jù)進(jìn)行全局的狀態(tài)管理。
4.4)用法
export function Sub() { const [data, updateData] = useStore() return <div> counter {data.counter} <button onClick={() => updateData({ counter: data.counter + 1 })}>+</button> </div> }
一個(gè)簡(jiǎn)單的 Sub 組件中,直接調(diào)用 useStore 可以方便進(jìn)行同步狀態(tài)管理和內(nèi)容更新。下面添加一個(gè)方法,用于處理異步任務(wù)。
4.5)添加異步方法
在 store 類中添加一個(gè)異步方法:
class Store { /* 其他方法*/ // 添加異步管理 asyncOperation(): Observable<any> { return of(/* Your async operation result */).pipe( switchMap((result) => { // 處理異步操作的結(jié)果,并更新狀態(tài) this.updateState({ counter: result }); return of(result); }), catchError((error) => { // 處理錯(cuò)誤 console.error('Error in async operation:', error); return of(null); }) ); } }
asyncOperation 是一個(gè) store 異步方法,使用 of 操作符,通過(guò)管道 switchMap 處理異步任務(wù),并返回新的可觀察對(duì)象,然后使用 catchError 處理錯(cuò)誤。
4.6) RxJS 作為狀態(tài)管理的優(yōu)點(diǎn)
- 可以借助強(qiáng)大的 RxJS 異步數(shù)據(jù)處理能力
- 配合 React hooks 可以磨平 RxJS 代碼層面對(duì)React代碼的入侵
- 熟悉 RxJS 的小伙伴,可以擁抱更加廣泛的 JS 生態(tài)
- 適合大型項(xiàng)目
4.7) 缺點(diǎn)
- 對(duì)新手并不友好
- RxJS 學(xué)習(xí)曲線比較高
- 不適合小型項(xiàng)目
五、小結(jié)
本文主要關(guān)注 RxJS 作為狀態(tài)管理的能力,通過(guò)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 Store 配合 BehaviorSubject 與 React hooks 進(jìn)行配合實(shí)現(xiàn)一個(gè)簡(jiǎn)單的全局狀態(tài)管理方案。同時(shí)也給出了異步數(shù)據(jù)的處理方案。本文需要對(duì) RxJS 和 React 以及 React 狀態(tài)管都比較熟悉,借助 RxJS 強(qiáng)大的異步數(shù)據(jù)流處理能力與 React hooks 結(jié)合,能夠很好的磨平 RxJS 客觀對(duì)象對(duì)React 組件代碼的入侵,在代碼層面也保持了簡(jiǎn)潔。最后也希望本文能夠幫助到大家。
以上就是淺聊一下為什么能用RxJS取代Redux的詳細(xì)內(nèi)容,更多關(guān)于RxJS取代Redux的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
深入理解JavaScript系列(29):設(shè)計(jì)模式之裝飾者模式詳解
這篇文章主要介紹了深入理解JavaScript系列(29):設(shè)計(jì)模式之裝飾者模式詳解,裝飾者用用于包裝同接口的對(duì)象,不僅允許你向方法添加行為,而且還可以將方法設(shè)置成原始對(duì)象調(diào)用(例如裝飾者的構(gòu)造函數(shù)),需要的朋友可以參考下2015-03-03微信小程序?qū)崿F(xiàn)星星評(píng)價(jià)效果
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)星星評(píng)價(jià)效果,支持多個(gè)條目評(píng)價(jià),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11微信小程序 列表的上拉加載和下拉刷新的實(shí)現(xiàn)
本文主要介紹了微信小程序中實(shí)現(xiàn)列表的上拉加載和下拉刷新的方法。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04Bootstrap彈出帶合法性檢查的登錄框?qū)嵗a【推薦】
這篇文章主要介紹了Bootstrap彈出帶合法性檢查的登錄框?qū)嵗a【推薦】的相關(guān)資料,需要的朋友可以參考下2016-06-06JavaScript中的偽數(shù)組用法及說(shuō)明
這篇文章主要介紹了JavaScript中的偽數(shù)組用法及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02JS實(shí)現(xiàn)部分HTML固定頁(yè)面頂部隨屏滾動(dòng)效果
這篇文章主要介紹了JS實(shí)現(xiàn)部分HTML固定頁(yè)面頂部隨屏滾動(dòng)效果,涉及JavaScript響應(yīng)onscroll事件動(dòng)態(tài)操作頁(yè)面元素屬性的相關(guān)技巧,需要的朋友可以參考下2015-12-12JavaScript實(shí)現(xiàn)移動(dòng)端橫豎屏檢測(cè)
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)移動(dòng)端橫豎屏檢測(cè),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07使用Echarts設(shè)置地圖并觸發(fā)點(diǎn)擊事件的代碼
這篇文章主要給大家介紹了關(guān)于使用Echarts設(shè)置地圖并觸發(fā)點(diǎn)擊事件的的相關(guān)資料,ECharts是一款基于JavaScript的數(shù)據(jù)可視化庫(kù),可以用于創(chuàng)建各種類型的交互式圖表,包括地圖,需要的朋友可以參考下2023-09-09javascript獲取不重復(fù)的隨機(jī)數(shù)的方法比較
js永不重復(fù)隨機(jī)數(shù)實(shí)現(xiàn)代碼比較2008-09-09