動態

詳情 返回 返回

為什麼能用 RxJS 取代 Redux ? - 動態 詳情

RxJS 在現在的前端用比較少,但是 RxJS 作為響應式和函數式編程的集大成者,似乎被前端開發者遺忘,可能是學習難度大,可能是有更加方便的解決方案。

不是因為 Redux 更具有性價比,而是 RxJS 可以打開更大的 JS 生態空間

下面我們先回顧一下 Redux 是如何運作開始。
一、Redux 創建一個 Store 做了哪些事情?

以上是一個簡單的 Redux 的工作流。從 reducer 到視圖派發更新的整個流程

Redux 通常在單頁面應用中,與React結合,他的基本使用流程。

定義 Reducer 函數
使用 createStore 函數傳入 Reducer 創建 store
訂閲函數 store
派發類型更新數據。

以下是一個官網的例子:
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' })

創建一個 Redux 其實也是需要訂閲(subscribe)數據。才能使用 dispatch 來派發行為到 reducer 裏面。
二、React Redux 與 React 結合
React Redux 是 React 官方與 Redux 結合,方便在 React 組件中使用 Redux。提供了:

Provider 組件
鈎子函數
...

2.1)Redux 的難點

初學 Redux 難點就是熟練根據自己的業務完成此流程。

2.2)中心化
Redux 是將數據集中到一個 store 庫,集中化數據管理,在大型項目中,你可能不想講數據集中化,Redux 在新的版本 Redux Toolkit 有了分片等功能開始彌補 Redux 的問題。
初學 Redux 其實還是有一定難度的,需要靈活使用 reducer 與 dispatch, 還需要 React 進行結合。並且異步副作用在 Redux 中還不好處理。
2.3)異步任務處理
Redux 通常不能直接處理異步任務,通常配合

Redux-thunk

Redux-saga

對異步任務進行處理。基於以上我們知道了其實 Redux 其實也具有自己優點和缺點。
三、RxJS 為什麼可以替代 Redux ?


3.1)React 作為視圖層
類似於 React 和 Vue 等框架,雖然組件具有自己的狀態管理,但是在複雜數據關係時力不從心。於是演化出了 Redux 等數據層管理庫。但是 RxJS 本身基於事件流,擁有強大的處理數據流能力。與視圖層集合便擁有了強大的數據處理能力。
3.2)Redux 作為數據層
通過以上的簡介,可以理解 Redux 其實就是一個 store 作為數據層而存在。它通常具有有以下一些操作:

存儲數據
取出數據
改變數據
異步處理

3.3) RxJS 作為數據層可以這樣做
RxJS 是一個函數式和響應式的 JavaScript, 自帶響應式數據能力。
普通的可觀察對象,只產生一個可觀察對象數據。也沒有緩存數據的能力。明顯不好,但是 RxJS 實現了 Subject 系列,其中 BehaviorSubject 能夠自帶初始值,並且也有緩存能力,能夠實現跨組件的訂閲數據。
BehaviorSubject 是實現 Store 中狀態管理的最佳選擇。
四、一個簡單的 RxJS 實現 Store
4.1)思考
我們要實現一個 Store,我們基於 class 和 React 的 hooks 進行設計。在 Store 需要考慮跨越組件和和跨越頁面的狀態管理設計。

BehaviorSubject 行為主題具有函數數據和初始化能力,是作為狀態管理的最佳選擇

4.2)實現一個簡單的 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()

這個 Store 也非常簡單,在構造函數中創建行為主題,然後再 getState 中獲取狀態主題,已經在 updateState 中使用 next 方法更新主題,最後在 unsubscribe 中取消訂閲。
這裏我們實例化一個全局 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 是設計考慮在全局使用的,意味着這裏的 useStore 是具有跨越頁面和組件能力的。其中重要的方法 updateData 是通過在修改 Store 內部的數據進行全局的狀態管理。

4.4)用法
export function Sub() {
const [data, updateData] = useStore()

return <div>

counter {data.counter}
<button onClick={() => updateData({
  counter: data.counter + 1
})}>+</button>

</div>
}

一個簡單的 Sub 組件中,直接調用 useStore 可以方便進行同步狀態管理和內容更新。下面添加一個方法,用於處理異步任務。
4.5)添加異步方法
在 store 類中添加一個異步方法:
class Store {

/ 其他方法/

// 添加異步管理
asyncOperation(): Observable<any> {

return of(/* Your async operation result */).pipe(
  switchMap((result) => {
    // 處理異步操作的結果,並更新狀態
    this.updateState({ counter: result });
    return of(result);
  }),
  catchError((error) => {
    // 處理錯誤
    console.error('Error in async operation:', error);
    return of(null);
  })
);

}
}

asyncOperation 是一個 store 異步方法,使用 of 操作符,通過管道 switchMap 處理異步任務,並返回新的可觀察對象,然後使用 catchError 處理錯誤。
4.6) RxJS 作為狀態管理的優點

可以藉助強大的 RxJS 異步數據處理能力
配合 React hooks 可以磨平 RxJS 代碼層面對React代碼的入侵
熟悉 RxJS 的小夥伴,可以擁抱更加廣泛的 JS 生態
適合大型項目

4.7) 缺點

對新手並不友好
RxJS 學習曲線比較高
不適合小型項目

五、小結
本文主要關注 RxJS 作為狀態管理的能力,通過實現一個簡單的 Store 配合 BehaviorSubject 與 React hooks 進行配合實現一個簡單的全局狀態管理方案。同時也給出了異步數據的處理方案。本文需要對 RxJS 和 React 以及 React 狀態管都比較熟悉,藉助 RxJS 強大的異步數據流處理能力與 React hooks 結合,能夠很好的磨平 RxJS 客觀對象對React 組件代碼的入侵,在代碼層面也保持了簡潔。最後也希望本文能夠幫助到大家。

Add a new 評論

Some HTML is okay.