這篇文章帶給大家的內容是關於使用RxJS管理React應用程式狀態的介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
隨著前端應用的複雜度越來越高,如何管理應用的資料已經是一個不可迴避的問題。當你面對的是業務場景複雜、需求變動頻繁、各種應用資料互相關聯依賴的大型前端應用時,你會如何去管理應用的狀態資料呢?
我們認為應用的資料大體上可以分為四類:
RxJS
天生就適合寫非同步和基於事件的程序,那麼狀態資料用什麼去管理呢?還是用RxJS
嗎?合不合適呢?
我們去研究和學習了前端社群已有的優秀的狀態管理解決方案,也從一些大牛分享的關於用RxJS
設計資料層的構想和實踐中得到了啟發:
RxJS
完全可以實現諸如Redux
,Mobx
等管理狀態資料的功能。 observable
來表達,則可以藉助RxJS
基於序列且可回應的的特性,以流的方式自由地拼接和組合各種類型的數據,能夠更優雅更有效率地抽像出可重複使用可擴充的商業模式。 基於上述兩點原因,最後決定基於RxJS
來設計一套管理應用程式的狀態的解決方案。
原理介紹
對於狀態的定義,通常認為狀態需要滿足以下3個條件:
event
或action
對值進行轉換,從而得到新的值。 那麼,RxJS
適合用來管理狀態資料嗎?答案是肯定的!
首先,因為Observable
本身就是多個值的推送集合,所以第一個條件是滿足的!
其次,我們可以實作一個使用dispatch action
模式來推送資料的observable
來滿足第二個條件!
眾所周知,RxJS
中的observable
可以分成兩種類型:
cold observable
: 推送值的生產者(producer
)來自observable
內部。
observable
建立時被定義下來,不可改變。 producer
與觀察者(observer
) 是一對一的關係,即是單播的。 observer
訂閱時,producer
都會把預先定義好的若干個值依序推送到observer
。 hot observable
: 推送值的producer
來自observable
外部。
producer
與observer
是一對多的關係,即是多播的。 observer
訂閱時,會將observer
註冊到觀察者清單中,類似於其他函式庫或語言中的addListener
的工作方式。 producer
被觸發或執行時,會將值同時推送給所有的observer
;也就是說,所有的observer
共享了hot observable
推送的值。 RxJS
提供的BehaviorSubject
就是一個特殊的hot observable
,它向外暴露了推送資料的介面next
函數;並且有「目前值」的概念,它保存了發送給observer
的最新值,當有新的觀察者訂閱時,會立即從BehaviorSubject
那接收到「目前值」。
那麼這說明使用BehaviorSubject
來更新狀態並保存狀態的目前值是可行的,第三個條件也滿足了。
簡單實作
請看以下的程式碼:
import { BehaviorSubject } from 'rxjs'; // 数据推送的生产者 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; // 状态的初始值 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);
執行程式碼控制台會印出三個值:
Console 1 2 4
上面的程式碼簡單實作了一個簡單管理狀態的範例:
plus
之後的狀態值: 2toDouble
之後的狀態值: 4實作方法挺簡單的,就是使用BehaviorSubject
來表達狀態的目前值:
dispatch
函数使producer
函数执行producer
函数在内部调用了BehaviorSubject
的next
函数,推送了新数据,BehaviorSubject
的当前值更新了,也就是状态更新了。不过写起来略微繁琐,我们对其进行了封装,优化后写法见下文。
我们自定义了一个操作符state
用来创建一个能够通过dispatch action
模式推送新数据的BehaviorSubject
,我们称她为stateObservable
。
const count$ = state({ // 状态的唯一标识名称 name: "count", // 状态的默认值 defaultValue: 1, // 数据推送的生产者函数 producer(next, value, action) { switch (action.type) { case "plus": next(value + 1); break; case "toDouble": next(value * 2); break; } } });
在你想要的任意位置使用函数dispatch
派遣action
即可更新状态!
dispatch("count", { type: "plus" })
RxJS
的一大优势就在于能够统一同步和异步,使用observable
处理数据你不需要关注同步还是异步。
下面的例子我们使用操作符from
将promise
转换为observable
。
observable
作为状态的初始值(首次推送数据)const todos$ = state({ name: "todos", // `observable`推送的数据将作为状态的初始值 initial: from(getAsyncData()) //... });
producer
推送observable
const todos$ = state({ name: "todos", defaultValue: [] // 数据推送的生产者函数 producer(next, value, action) { switch (action.type) { case "getAsyncData": next( from(getAsyncData()) ); break; } } });
执行getAsyncData
之后,from(getAsyncData())
的推送数据将成为状态的最新值。
由于状态todos$
是一个observable
,所以可以很自然地使用RxJS
操作符转换得到另一个新的observable
。并且这个observable
的推送来自todos$
;也就是说只要todos$
推送新数据,它也会推送;效果类似于Vue
的计算属性。
// 未完成任务数量 const undoneCount$ = todos$.pipe( map(todos => { let _conut = 0; todos.forEach(item => { if (!item.check) ++_conut; }); return _conut; }) );
我们可能会在组件的生命周期内订阅observable
得到数据渲染视图。
class Todos extends React.Component { componentWillMount() { todos$.subscribe(data => { this.setState({ todos: data }); }); } }
我们可以再优化下,利用高阶组件封装一个装饰器函数@subscription
,顾名思义,就是为React组件订阅observable
以响应推送数据的变化;它会将observable
推送的数据转换为React组件的props
。
@subscription({ todos: todos$ }) class TodoList extends React.Component { render() { return ( <p className="todolist"> <h1 className="header">任务列表</h1> {this.props.todos.map((item, n) => { return <TodoItem item={item} key={item.desc} />; })} </p> ); } }
使用RxJS
越久,越令人受益匪浅。
observable
序列提供了较高层次的抽象,并且是观察者模式,可以尽可能地减少各组件各模块之间的耦合度,大大减轻了定位BUG和重构的负担。observable
序列来编写代码的,所以遇到复杂的业务场景,总能按照一定的顺序使用observable
描述出来,代码的可读性很强。并且当需求变动时,我可能只需要调整下observable
的顺序,或者加个操作符就行了。再也不必因为一个复杂的业务流程改动了,需要去改好几个地方的代码(而且还容易改出BUG,笑~)。所以,以上基于RxJS
的状态管理方案,对我们来说是一个必需品,因为我们项目中大量使用了RxJS
,如果状态数据也是observable
,对我们抽象可复用可扩展的业务模型是一个非常大的助力。当然了,如果你的项目中没有使用RxJS
,也许Redux
和Mobx
是更合适的选择。
这套基于RxJS
的状态管理方案,我们已经用于开发公司的商用项目,反馈还不错。所以我们决定把这套方案整理成一个js lib
,取名为:Floway
,并在github
上开源:
【相关推荐:react视频教程】
以上是使用RxJS管理React應用程式狀態的介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!