簡化action屬性更新
通常情況下,store中會有很多屬性,其中有些屬性更新會很頻繁,每一個屬性都需要寫一個action函數去更新,當這種需要變更的屬性越多時,會導致store中代碼量異常的龐大,可讀性也會降低。就如下面代碼一樣:
class TestStore {
@observable info = {} as IInfo;
@observable list = [] as IList;
@action
setInfo = (value: IInfo) => {
this.info = value;
}
@action
setList = (value: IList) => {
this.list = value;
}
}
引入typescript中keyof關鍵字使用,可以將上述action函數簡化如下:
class TestStore {
@observable info = {} as IInfo;
@observable list = [] as IList;
@action
setValue = <T extends keyof TestStore>(key: T, value: this[T]) => {
this[key] = value;
}
}
簡化store之間的相關依賴
callback實現Store之間的通信
比如StoreA中某個方法執行後需要調用StoreB中的方法
// /stores/StoreA.ts
class StoreA {
@action
methodA = (cb: () => void) => {
// coding...
if (cb) cb();
}
}
// /stores/StoreB.ts
class StoreB {
@action
methodB = () => {
// coding...
}
}
// /stores/index.ts
export default {
storeA: new StoreA(),
storeB: new StoreB(),
}
頁面調用
// index.tsx
import React from 'react';
import stores from './stores/index.ts';
import Main from './components/Main.tsx';
const Index = () => {
return <Provider {...stores}>
<Main {...props}></Main>
</Provider>
}
// Main.tsx
import React from 'react';
interface IProps {
storeA?: StoreA;
storeB?: StoreB;
}
const Main = (props: IProps) => {
const { storeA, StoreB } = props;
const { methodA } = storeA;
const { methodB } = storeB;
const handleClick = () => {
methodA(methodB);
}
return <span onClick={handleClick}></span>
}
promise實現Store之間的通信
// /stores/StoreA.ts
class StoreA {
@action
methodA = () => {
return new Promise((resolve) => {
// coding...
resolve();
})
}
}
頁面調用
const Main = (props: IProps) => {
const { storeA, StoreB } = props;
const { methodA } = storeA;
const { methodB } = storeB;
const handleClick = () => {
methodA().then(() => {
methodB();
});
}
return <span onClick={handleClick}></span>
}
通過根級Store調度子級Store實現通信
引入根級store,將上面store組織方式改成如下形式:
// /stores/StoreA.ts
class StoreA {
rootStore: RootStore;
constructor(rootStore) {
this.rootStore = rootStore;
}
@action
methodA = () => {
// coding...
this.rootStore.storeB.methodB();
}
}
// /stores/StoreB.ts
class StoreB {
rootStore: RootStore;
constructor(rootStore) {
this.rootStore = rootStore;
}
@action
methodB = () => {
// coding...
}
}
class RootStore {
storeA: StoreA;
storeB: StoreB;
constructor() {
this.storeA = new StoreA(this),
this.storeB = new StoreB(this),
}
}
// /stores/index.ts
export default {
rootStore: new RootStore(),
}
頁面調用
const Main = (props: IProps) => {
const { storeA, StoreB } = props;
const { methodA } = storeA;
const { methodB } = storeB;
const handleClick = () => {
methodA();
}
return <span onClick={handleClick}></span>
}
降低store的顆粒度
有些項目頁面的業務邏輯、交互異常的複雜,如果把這些業務邏輯都堆在一個store中將會使得store的代碼量異常的龐大,就如上圖store有着上千行的代碼量。這將會嚴重降低代碼的可讀性,如果繼續迭代甚至會影響後人的開發效率。
當然,我們可以上面拆分成多個store來解決問題,這種場景不是我本節考慮的,我想講述的是以下這種場景:
假如我們要做這麼一個表格,並且後端給的數據結構是這樣子的:
quote數組中的每一個對象對應着每一個報價條目
如果每條報價條目數據需要改變時,就需要去遍歷quote數組找到對應的報價條目對象,重新賦值,寫一個函數就行了。如果報價條目相關的業務邏輯(校驗、變更值等等)特別的多呢?那麼也要書寫很多的函數去實現,這些跟報價條目相關的業務代碼都堆在一個store中肯定會使store更加的臃腫。
肯定有同學會説,把這部分拆分到一個獨立的store中不就可以了嗎?但是表格數據作為一個整體,這種業務拆分是不容易實現的,那麼有沒有其他方法呢?
肯定有的,在mobx中每一個報價條目對象都是一個observable對象,我們可以把這個對象抽出來放到另一個store中,而之前的store存放的只是一個引用,描述的可能不太清楚,附上代碼説明一下:
// quotation.ts
class Quotation {
@observable quoteId: string = '';
@observable partNum: string = '';
@observable partName: string = '';
constructor(quotation: any) {
Object.assign(this, {...quotation});
}
@action
...
}
// tableStore.ts
class TableStore {
@observable tableData: ITable = [] as ITable;
assemble = (needResults: any, quotations: any) => {
const data: ITable = [];
needResults.forEach(v => {
quotations.forEach(p => {
if (p.demandItemId === v.demandItemId) {
data.push({
need: v,
quote: p.result.map(o => {
return new Quotation(o);
})
})
}
})
})
}
/** 獲取報價項次、報價結果 */
@action
fetchTableData = async () => {
Promise.all([fetchNeedResults(), fetchQuotationResults()]).then((res) => {
if (res[0].code === 200 && res[1].code === 200) {
const needResults = res[0].data;
const quotations = res[1].data;
/** 組裝表格數據 */
this.tableData = this.assemble(needResults, quotations);
}
});
};
}
這麼設計store的組織方式可以更加靈活的控制store的顆粒度,同時也能很好的避免store的巨大化以及多人操作同一個store的場景。比如圖中可以類似將“表格部分”拆分出“需求部分”、“報價部分”,當多人同時開發時,每一個人只需要負責自己模塊中的樣式、業務邏輯、數據存儲,在一定程度上形成了一個閉環,對於每個開發來説都是有益的,而且這樣一種組織代碼的方式也會增強代碼的可讀性以及複用性,方便後期的維護。