/ 前端工程

"有条理地"编写带有副作用的 redux action

本文主要是一个代码编写流程的梳理,侧重点在于”有条理”,而不在于相关技术的介绍。目的是为了在编写业务代码时,更加清晰有章法地去做事。下面关于技术的介绍,目的也在于让这些条理更加清晰。

相关技术

redux, redux-actions, redux-saga

场景说明

在最近的一个项目中,使用到了 saga 来处理 redux action 的副作用,当我们需要发起一个有副作用的 action 时,比如需要发起一个 action, 这个 action 会先发起一个网络请求获取数据,获取到数据后,根据返回的结果判断是否需要发起另一个请求,然后再根据返回的结果去更新 redux 的 store。

代码组织结构

types
├── index.d.ts
├── api.d.ts
…
apis
├── index.ts
 …
store
├── actionTypes.ts
├── actions
│   ├── index.ts
├── reducers
│   ├── index.ts
├── saga
│   ├── index.ts

为了更好地组织项目代码,各种类型的代码都是分类管理的,从上面的场景,可以分成这几个类型的代码:

  • types/*.ts 数据类型定义,需要定义这些数据类型: API 方法的接收参数类型、API 获取到的数据的类型、action 中 payload 需要的额外数据的类型
  • apis/index.ts 提供调用 API 的方法,给组件或者 saga 使用
  • store/actionTypes.ts 定义 action 的类型,统一暴露出来,方便 action 的管理及使用
  • store/actions/index.ts 通过 action 的 creator 来创建可以直接在组件或者 saga 中使用的 action,免除了手动 dispatch action 的麻烦
  • store/reducers/index.ts 定义 action 的 reducer
  • store/saga/index.ts 处理 action 的副作用

从这里可以发现,想编写一个带有副作用的 action 需要跨越不少文件夹,写不少代码。我刚开始写这一套东西的时候就有点乱,导致效率极低。写本文的初衷就是希望梳理一下这片东西,让代码的书写过程更流畅,不必要不断地停顿然后思考,还有各种文件夹乱跳来跳去。

实现”有条理"的方式

  1. 在实现这个副作用的数据流之前,最确定的东西是 API,即 API 方法的接收参数和返回数据类型可以最早确定,因此先定义好 API 方法的接收参数和返回数据的类型 ==> types/api.d.ts
  2. 思考相关的 action 可能会对 store 造成什么影响(在这一步其实也要开始构想 store 结构上的变化的雏形了),要达成这种影响需要哪些额外的数据,定义这些额外的数据的类型,比如需要一个条目的 ID 或者 索引,用来更新 store 中相应的条目,在这一步定义好这些额外的数据的类型 ==> types/index.d.ts
  3. 有了 API 需要的所有数据的类型后,可以编写 API 请求的方法 ==> apis/index.ts
  4. API 相关的准备工作做完了,回到我们的主题,这是一个 action 的副作用,因此在这一步定义好整个副作用中涉及到的所有 action 的类型 ==> store/actionTypes.ts
  5. 有了 action 类型,就可以实际创建 action 了,在这一步,由于第一步的时候已经考虑过了 payload 需要哪些数据及其类型,所以可以方便地创建 action ==> store/actions/index.ts
  6. 由于 reducer 中会涉及到 store 的数据的结构,因此在所有流程中是相对更复杂的,所以最后写 reducer 中的东西,先在 saga 中把副作用中的数据流串起来(注意先写测试代码) ==> store/saga/index.ts
  7. 最终编写需要处理的 action 的 reducer(注意先写测试代码) ==> store/reducers/index.ts

总结

从这里可以看出,要写完一个带有副作用的 action,工作量还是不小,但梳理出来条理之后,效率还是可以得到提升的。不禁感叹React 生态系统真是博大精深,有条理地编写代码,才能在这个生态系统里面游刃有余,以后应该还是需要做一些东西的梳理的,包括本文的条理也可能不是最优的方法,不断在实践中去发现然后总结,再修正,用更高地效率编写更好的代码。