React?中使用?RxJS?優(yōu)化數(shù)據(jù)流的處理方案
正文
現(xiàn)在我們比較熟悉的是使用 functional component 和 hooks 來處理 react 邏輯。熟悉 Angular 的用戶可能比較熟悉通過 RxJS 來處理異步和數(shù)據(jù)狀態(tài)。那么我們看一下 React 中使用 RxJS 會不會有什么優(yōu)勢呢?
一般來說,處理組件中的數(shù)據(jù)流無非三種情況:
- Component 中 props 的變化
- 用戶在界面上操作,觸發(fā) event 修改 component 的數(shù)據(jù)
- Component 中監(jiān)聽的 store 觸發(fā)數(shù)據(jù)變化
下面我們看一個很簡單的例子:
有一個 component,顯示 input 中輸入的數(shù)據(jù)。邏輯也很簡單:
export function ShowInput(props: { data: string; }): JSX.Element { return <>{props.data}</>; }
也就是第一種情況,component 的狀態(tài)是通過,props 傳遞進來的。
這當然沒有問題,當數(shù)據(jù)變化的時候重新渲染即可。假設我們每一次輸入就會觸發(fā)一次 api call,然后把 api 返回的內(nèi)容顯示在界面上。這里就需要處理兩個問題:
- 盡可能減少 api call 的次數(shù)(比如用戶輸入有 500ms 的停頓以上時,我們認為用戶已經(jīng)輸入結束,才開始 call api)
- 用戶如果多次輸入,會有多次 api call,那么后面 api 返回的數(shù)據(jù)應該永遠覆蓋前面 api 返回的數(shù)據(jù)。
- 暫時不考慮 api 可能出錯,需要重新 call api 的情況
熟悉 RxJS 的話,會知道,這是一個非常簡單的數(shù)據(jù)流的問題,如果我們把 props 的數(shù)據(jù)看作是一個數(shù)據(jù)流的話,就可以非常簡單的解決了。
const apiRespons$ = data$.pipe( debounceTime(500), switchMap(data => getApiResponse(data)), ); // Mock API call function getApiResponse(data: string) { return of(data + ' data from api').pipe(delay(1000)); }
那么,問題就來了,如何將 props data 轉(zhuǎn)換成 stream, 又如何將處理完的 stream 轉(zhuǎn)換成 component state 呢。
這里就需要引入一個庫: rxjs-hooks
用法一: 將 stream 轉(zhuǎn)換為 componet state.
比如我們已經(jīng)得到了 apiResponse$,如何在 component 中顯示的呢?
const apiRespons$ = data$.pipe( debounceTime(500), switchMap(data => getApiResponse(data)), ); const apiResponse = useObservable(() => apiRespons$);
那么如何結合 props 的變化使用呢?
用法二: 將 props 轉(zhuǎn)換為 stream useObservable 還可以輸入兩個參數(shù):
- 狀態(tài)的初始值 (類似,useState)
- 監(jiān)聽變量(類似 useEffect 的數(shù)組參數(shù)),轉(zhuǎn)換為 stream 作為函數(shù)的參數(shù)
完整的代碼會變成這樣:
export function ShowInput(props: { data: string; }): JSX.Element { const apiResponse = useObservable((_, input$) => input$.pipe( debounceTime(500), switchMap(([data]) => getApiResponse(data)), ), '', [props.data]); return <>{apiResponse}</>; }
當然,也有可能,數(shù)據(jù)的變化時當前 component 的,不是 props 傳進來的。也就是說這個 input 可能會是在當前 component 中。
當然,我們簡單的把 input 放在當前的 componnet 中,把監(jiān)聽內(nèi)容從 props 換成 state. 也比較簡單。
const [data, setData] = useState<string>(); const apiResponse = useObservable((_, input$) => input$.pipe( debounceTime(500), switchMap(([inputData]) => getApiResponse(inputData || '')), ), '', [data]);
那么,有沒有更簡單一點的方法呢?
就涉及到用法三:將 event 函數(shù)的調(diào)用自動轉(zhuǎn)換為 stream
const [onInputChange, apiResponse] = useEventCallback((data$: Observable<string>) => data$.pipe( debounceTime(500), switchMap((data) => getApiResponse(data || '')), ), '');
這就將 useState 和 useObservable 合為一體。第一個參數(shù)時 event 函數(shù),第二個參數(shù)時 state。
當然,如果有使用 redux observable 的話,就可以很好的跟 rxjs-hooks 合為一體。
那么,問題來了,使用數(shù)據(jù)流的方式來處理數(shù)據(jù)有什么好處呢?
- RxJS 內(nèi)置了很多數(shù)據(jù)流的處理方式,可以大大的簡化我們處理數(shù)據(jù)的流程。類似于異步中的 lodash.
- 在 React 中我們往往會同時使用 Redux 和 Hooks, 某種程度上說,我們會使用 Redux 處理全局或者說大的狀態(tài)管理,hooks 處理 component 層,或者說小的數(shù)據(jù)狀態(tài)管理。使用 redux observable 和 rxjs hooks 不失為一種溝通全局狀態(tài)和局部狀態(tài)的好的方式。
- 我們直到 redux 時跨平臺的。但是有些時候我們并不希望把所有的數(shù)據(jù)狀態(tài)都封裝在 redux 中。如果要實現(xiàn)數(shù)據(jù)狀態(tài)的跨平臺,而不使用 redux 的話,rxjs 實現(xiàn)一個狀態(tài)關機工具無非是最簡單的。因為一個 subject 就是一個最簡單的 store. 讓我們的主要邏輯不依賴于框架,是最好的多平臺共享的方式。
對于 component 層的局部狀態(tài),邏輯共享:
react angular | / hooks component store | / js rxjs store
對于 redux 狀態(tài)共享
react angular | / redux observable
以上就是React 中使用 RxJS 優(yōu)化數(shù)據(jù)流的處理方案的詳細內(nèi)容,更多關于React RxJS 優(yōu)化數(shù)據(jù)流的資料請關注腳本之家其它相關文章!
相關文章
react?hooks深拷貝后無法保留視圖狀態(tài)解決方法
這篇文章主要為大家介紹了react?hooks深拷貝后無法保留視圖狀態(tài)解決示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06React如何使用create-react-app創(chuàng)建react項目
這篇文章主要介紹了React如何使用create-react-app創(chuàng)建react項目問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03react-native使用leanclound消息推送的方法
這篇文章主要介紹了react-native使用leanclound消息推送的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08詳解前端路由實現(xiàn)與react-router使用姿勢
本篇文章主要介紹了詳解前端路由和react-router使用姿勢,詳細的介紹了react-router的用法,有興趣的可以了解一下2017-08-08