V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
FaiChou
V2EX  ›  JavaScript

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

  •  
  •   FaiChou · 2019-12-07 15:43:15 +08:00 · 2803 次点击
    这是一个创建于 1594 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    before

    这是之前的页面, 个人中心有「商品订单」和「服务订单」的入口, 可以跳转到不同的 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() {}
    ...
    

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

    after

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

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

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

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

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

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

    数据源不止一个的话,就会给项目维护埋坑。
    FaiChou
        3
    FaiChou  
    OP
       2019-12-07 18:30:51 +08:00
    @cfy 谢谢 「数据源不止一个的话,就会给项目维护埋坑」真的是这样子的, 但是业务场景不在乎代码. 站在开发者角度, 应该尽可能给后人提供容易维护的代码.
    FaiChou
        4
    FaiChou  
    OP
       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 兼容.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5194 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 07:33 · PVG 15:33 · LAX 00:33 · JFK 03:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.