3
头图

简化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;
  }
}

引入typescriptkeyof关键字使用,可以将上述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实现通信

image.png
引入根级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的颗粒度

image.png
有些项目页面的业务逻辑、交互异常的复杂,如果把这些业务逻辑都堆在一个store中将会使得store的代码量异常的庞大,就如上图store有着上千行的代码量。这将会严重降低代码的可读性,如果继续迭代甚至会影响后人的开发效率。

当然,我们可以上面拆分成多个store来解决问题,这种场景不是我本节考虑的,我想讲述的是以下这种场景:

image.png

假如我们要做这么一个表格,并且后端给的数据结构是这样子的:

image.png

quote数组中的每一个对象对应着每一个报价条目

image.png

如果每条报价条目数据需要改变时,就需要去遍历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的场景。比如图中可以类似将“表格部分”拆分出“需求部分”、“报价部分”,当多人同时开发时,每一个人只需要负责自己模块中的样式、业务逻辑、数据存储,在一定程度上形成了一个闭环,对于每个开发来说都是有益的,而且这样一种组织代码的方式也会增强代码的可读性以及复用性,方便后期的维护。


记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。


引用和评论

0 条评论