MST Request Type —— 简单的MST中的请求处理工具

131 阅读5分钟

处理异步请求是前端应用逻辑中最常见的需求之一。在前端应用中,每个异步请求除了自身状态,还有伴随状态和方法,如请求返回数据,Loading状态,错误处理,重置请求数据等等。使用统一的数据管理(Model)方案,在请求数量增多后,在Model中就会存在大量的请求伴随状态,伴随状态又需要根据请求状态更改,这增加了很多重复劳动。

虽然市面上已经有了不少这个问题的解决方案,比如React Query,RTK Query,自定义hooks等,但配合Mobx State Tree的解决方案却很少,只有官方网站上提到mst-query。不过,mst-query学习成本很高,基本改变了原来Mobx State Tree的使用方式,在Mobx State Tree学习曲线已经不太友好的情况下,我并不倾向于再引入更多的复杂度。

所以,为了简单的解决这个常见问题,我用Mobx State Tree中自定义model type的思路,制作了一个简单的自定义type,力图最小化学习、使用成本,只提供异步请求必需的伴随功能,并尽可能为使用者提供灵活度。这个库非常小,只有4个必须使用的API,但是可以减少大部分的异步请求处理成本,Mobx State Tree的使用者可以尝试一下。

链接

www.npmjs.com/package/mst…

安装

npm i mst-request-type -S

注意:需要自行安装mobx-state-tree的5.0.0以上版本。

使用

import Request from 'mst-request-type'

在MST model中声明Request类型:

types.model('NAME').props({ ..., asyncData: Request, ... })

asyncData对应一个需要从异步请求获取的数据

在React中使用:

读取props:<div>{asyncData.PROPS}</div>
调用actions: asyncData.ACTIONS()

可以看出,mst-request-type提供了一个custom model type(文中import成Request),异步请求需要的属性和方法都在这个type上。

示例

// request function
const getCat = async ({ controller }) => {
  ...

  return output
}

// Declare model
import Request from 'mst-request-type'

const Cat = types
  .model('Cat')
  .props({
    cat: Request,
  })
  .actions(self => ({
    getCat: flow(function* () {
      self.cat.set(SCat.getCat)

      yield self.cat.fetch()
    }),
  }))

// Access in React
const App = () => {
  const { Cat: model } = useStore()

  useEffect(() => {
    model.getCat()
  }, [])

  return (
    <div>
      <h1>Cat</h1>
      <div>{model.cat.loading.toString()}</div>
      {model.cat.data}
      <button onClick={() => model.cat.refetch()}>One more</button>
    </div>
  )
}

export default observer(App)

APIs

常用的API只有4个:loadingdataset(request, reject?)fetch(params?)

props(属性)

绝大多数情况下,只需要用到loadingdata

status

请求的当前状态,共有'init', 'pending', 'success', 'error', 'canceled' 5种

loading

一个根据status得到的计算值,在status是pending的时候返回true

data

请求返回数据,数据由请求函数返回,默认为[],data数组中的对象是非observable,也就是说对于Mobx State Tree而言,data整体是一个leaf节点,不是一颗子树

error

请求发生的错误,由请求函数抛出

token

一个可选的id,默认是'',可以通过option()设定,目前没有什么作用,Request实例由创建Request的model追踪。

actions(方法)

绝大多数情况下,只需要用到set()fetch()

set(request, reject?)

必须在fetch()之前调用,以设定一个request函数供fetch使用,否则调用fetch()时会报错

设置该Request type使用的request函数和错误处理函数,两个函数都会在后面的fetch()方法中调用。

每次调用set()都会调用reset()重制该Request中的data,error,status。

如果在option()中设定了once = trueset()只能调用一次。

这里多说一句为什么没有把set的功能直接做在create上。因为设计的思路是自定义的model type,如果初始化做到create上,在调用时会和其他的type产生比较明显的差异。另外,set本身也不可或缺,默认情况下,request函数是可以被修改的,所以采用了当前的设计方式。

fetch(params?)

默认params为{}

传入参数params调用set()设定的request函数。调用过程中会根据请求状态改变Request的status,data,error props,如果也设定了reject handler,则会被用来处理请求本身抛出的错误。

请求成功后,返回的数据会存在data属性中,请求错误,data[],error存在error属性中。

请求的参数会被保存在Request的实例中,如果fetch()没有传入参数,则会使用上一次的参数。

建议request函数始终返回数组保持一致性

reset()

清除dataerror属性,并将status设为'init'

setCancel(cancel: AbortController)

为该Request设定一个Abort controller用于终止请求。如果没有参数,则会默认设定一个新的Abort controller,供后面的cancel()使用。

注意:调用过setCancel()就会为该Request设定一个自己的Abort controller,这个controller会以{ controller }参数的形式传递给request函数,如果需要使用,需要在request函数中处理,不需要建议不要调用setCancel()方法。

cancel()

setCancel()配套,如果设置了Abort controller,调用cancel()会取消当前请求,并将status设定为'canceled'。如果没有设置Abort controller,会在console中打印一个warning。

refetch()

如果设定了Abort controller,则取消当前fetch(),清除当前data,并使用原参数再次调用fetch()。如果没有设定Abort controller,则清除当前data,直接使用原参数再次调用fetch()

刷新的快捷方法

option({ id, once = false }: { id?: string; once?: boolean })

设定改Request的token和是否只能被set()一次。token目前没有特殊用途,默认情况下,Request type可以被set()多次。

Issue

github.com/sherlockwan…