如何修改当前的 Redux Store 来应对项目需求更改?

2019-12-07 15:43:15 +08:00
 FaiChou

想不出来合适的标题, 可以有偿求解决方案, 这是由于业务新增需求导致不清楚应该如何解决.

这是之前的页面, 个人中心有「商品订单」和「服务订单」的入口, 可以跳转到不同的 tab (上面的 tab)页. App 是用 RN 写的, 用到了 redux + saga, 其中这俩订单页面的数据统一放到一个 state 中, 页面有分页功能, 从订单列表页面还可以跳转订单详情, 订单的操作有支付,取消订单,确认收货等, 可以在列表与详情中操作, 在详情中操作需要同步到列表, 所以详情页的数据也是取自这个 state. 使用 redux 好处是可以让数据放到内存中, 切换页面不会丢失数据. state 是这样的解构:

const INIT_STATE = {
  current: TAB[0],
  loading: true,
  allS: {
    page: 1,
    list: []
  },
  allG: {
    page: 1,
    list: []
  },
  unpayS: {
    page: 1,
    list: []
  },
  unpayG: {
    page: 1,
    list: []
  },
  unconfirmS: {
    page: 1,
    list: []
  },
  ...

对应的操作都是通过 saga 来处理:

function* handleFetch() {}
function* handleChangeTab() {}
function* handleRefresh() {}
function* handleCancelOrder() {}
function* handlePay() {}
...

到这里是没问题的, 功能挺完善, 但是新需求来了, 要增加一个页面, 这个页面是两个订单列表的组合, 通过调用一个接口, 分页获取订单, 按照时间的排序, 保留之前两个列表, 新增的这个页面上面有之前订单列表的入口:

这里就出现了几个比较棘手的问题, 先说一下我怎么实现的: 新的列表页不用 redux, 请求数据直接渲染列表, 当发生订单操作时候, 清理掉之前的订单列表的 redux 数据(比较偷懒)来解决多列表同步问题. 当跳转产品详情页时候, 产品详情的数据是取自之前列表, 怎么解决没有数据这个问题呢? 添加一个HACKaction, 当跳转详情之前, 先把数据 hack 到之前的列表中. 那么马上就遇到下面的问题, 当在详情里进行订单操作时候, 如何同步到新的列表? 如果是从之前列表跳转详情, 如何同步新的列表与旧的列表?

看来不使用 redux 来混合 redux 开发是死路一条, 那么我又想到了几种方案, 但都是有问题的:

方案一: 新的列表页面使用旧列表页面的 redux 数据, 新页面加载时候直接给旧列表发送请求, 一份数据多个列表使用. 这个方案不可行原因是新的列表是按照下单时间排序的, 可能会有「商品」「服务」「商品」这种混合订单, 没法满足需求.

方案二: 新建一个 state, 这个 state 给新的列表使用, 但会和旧的 state 共用一些 actions, 详情页面的数据取自两个 state, 因为都对应同一订单. 但是这个方案的问题也比较明显, 比如在详情页面选择支付, 会发送一个支付 action, 那么处理这个 action 的应该是哪一个呢?

暂时没有想到其他的解决方法, 问题比较长, 希望能够看得明白.

2957 次点击
所在节点    JavaScript
4 条回复
dremy
2019-12-07 17:11:07 +08:00
建议还是不要将这些页面数据存储到全局状态中共用,而是每个页面单独维护自己的数据状态,当然登录信息之类必须共用的除外
cfy
2019-12-07 17:32:55 +08:00
store 里加一个 flag,传递给订单列表页面;
如果需要展示新数据,跳转到订单列表页面之前,
发 api 请求更新 store,设置 flag ;更新 store 订单数据后再更改 flag ;
订单列表页面通过 store 获取 flag,看业务场景是先展示旧数据,还是等待新数据更新,就可以了。

数据源不止一个的话,就会给项目维护埋坑。
FaiChou
2019-12-07 18:30:51 +08:00
@cfy 谢谢 「数据源不止一个的话,就会给项目维护埋坑」真的是这样子的, 但是业务场景不在乎代码. 站在开发者角度, 应该尽可能给后人提供容易维护的代码.
FaiChou
2019-12-08 12:35:23 +08:00
解决了, 采用的方法是新增一个 redux state: anotherOrderList (起名的艺术).
它和之前的 reducer 共享一些操作 actions:

```
export function* watchOrderCalcel() {
yield takeLatest(types.SAGA_ORDER_CANCEL, handleCancel)
}
export function* watchOrderReceive() {
yield takeLatest(types.SAGA_ORDER_RECEIVE, handleReceive)
}
export function* watchOrderPay() {
yield takeLatest(types.SAGA_ORDER_PAY, handlePay)
}
export function* watchOrderEvaluation() {
yield takeLatest(types.SAGA_ORDER_EVALUATION, handleEvaluate)
}
```

新增俩给 anotherOrderList 使用的:

```
// ANOTHER ORDER LIST
export function* watchAnotherOrderFetch() {
yield takeLatest(types.SAGA_ANOTHER_ORDER_LIST_FETCH, handleAnotherFetch)
}
export function* watchAnotherOrderRefresh() {
yield takeLatest(types.SAGA_ANOTHER_ORDER_LIST_REFRESH, handleAnotherRefresh)
}
```

在订单详情里要处理下, 取两个 list 的数据:
```
const mapState = (state, ownProps) => {
const { navigation } = ownProps
const orderId = navigation.getParam('orderId')
if (orderId) {
const { orderList, anotherOrderList } = state
const l1 = orderList[orderList.current.value].list
const l2 = anotherOrderList.list
const cond = item => item.orderId === orderId
const data = l1.find(cond) || l2.find(cond)
return {
orderId,
orderStatus: data.orderStatus
}
}
return null
}
```

共享 actions 的方法里要做对新的 list 兼容.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/626815

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX