【问题标题】:Redux Saga - Complex control flowRedux Saga - 复杂的控制流
【发布时间】:2017-04-22 08:41:00
【问题描述】:

我来自 Redux Thunk,所以我是 Redux Saga 的新手。我已经设法实现了一些简单的 takeEvery 调用,但我正在为一个更复杂的解决方案而苦苦挣扎,想知道您是否能够为我指明正确的方向。

我正在创建一个仓库应用程序,它使用 Redux Persist 离线存储挑选的订单,然后在我有连接时定期将它们同步回服务器。为了同步它们,我需要按顺序独立进行两个 api 调用:

  1. 更新拣货数量
  2. 确认选择

我在下面附上了我的 Redux 状态示例。如果您查看 ordersToSync,我必须首先使用第一种方法(单独)回发 PickedQuantity 和 PickingListDetailId,并使用第二种方法通过 PickListId 确认选择。

到目前为止,我已经设法创建了一个 es6 生成器来模拟我想要的行为,并使用一些标志来检查连接性、数据是否正在同步或是否有错误。如果您将我附加的代码复制并粘贴到 https://stephengrider.github.io/JSPlaygrounds/ 并检查您使用的控制台,以查看所需的结果。

我正在为将其应用于 Redux Saga 的概念而苦苦挣扎,因此该进程可以在后台作为非阻塞调用工作。谁能帮我指出正确的方向?

非常感谢。

    // Example Sync Queue (Persisted Redux state)
    const ordersToSync = [
        {
        "pickingListId": 2362,
        "itemsPicked": [
          {
            "PickingListDetailId": 3115,
            "ProductId": 3387,
            "ProductSKU": "123XP",
            "ProductTitle": "Frameset",
            "PickQuantity": 2,
            "PickedQuantity": 2
          },
          {
            "PickingListDetailId": 3114,
            "ProductId": 3386,
            "ProductSKU": "123XP",
            "ProductTitle": "Frameset",
            "PickQuantity": 3,
            "PickedQuantity": 1
          },
          {
            "PickingListDetailId": 3116,
            "ProductId": 3385,
            "ProductSKU": "123XP",
            "ProductTitle": "Frameset",
            "PickQuantity": 4,
            "PickedQuantity": 4
          }
        ]
      },
      {
        "pickingListId": 2374,
        "itemsPicked": [
          {
            "PickingListDetailId": 3105,
            "ProductId": 3088,
            "ProductSKU": "123XP",
            "ProductTitle": "Frameset",
            "PickQuantity": 1,
            "PickedQuantity": 1
          }
        ]
      },
      {
        "pickingListId": 2322,
        "itemsPicked": [
          {
            "PickingListDetailId": 3101,
            "ProductId": 3187,
            "ProductSKU": "123XP",
            "ProductTitle": "Frameset",
            "PickQuantity": 2,
            "PickedQuantity": 2
          },
          {
            "PickingListDetailId": 3118,
            "ProductId": 3286,
            "ProductSKU": "123XP",
            "ProductTitle": "Frameset",
            "PickQuantity": 3,
            "PickedQuantity": 1
          },
          {
            "PickingListDetailId": 3125,
            "ProductId": 3325,
            "ProductSKU": "123XP",
            "ProductTitle": "Frameset",
            "PickQuantity": 4,
            "PickedQuantity": 4
          }
        ]
      },
    ];

    // Represents Redux Reducer
    const error = false; // Flip if error comes back from axios request
    const syncing = false; // Flip whilst axios request does its thing
    const connectionType = 'WIFI'; // Toggled by

    // ES6 generator for dispatching sync actions
    function* OrderIterator() {
      // If we have a suitable connection (NetInfo connection type)
      if (connectionType === 'WIFI') {
        // If we are not already syncing some data
        // And we have no errors
        if (!syncing && !error) {
          for (const order of ordersToSync) {
            for (const item of order.itemsPicked) {
              // Dispatch updatePickQuantityAction
              // 1. Flip the syncing state to true UPDATE_PICK_QUANTITY_START
              // 2. If there is an error stop everything and flip the error state to true UPDATE_PICK_QUANTITY_FAIL
              // 3. If everything goes well with the request, flip the syncing state to false and carry on UPDATE_PICK_QUANTITY_SUCCESS
              yield console.log(`this.props.updatePickQuantityAction(${item.PickedQuantity}, ${item.PickingListDetailId});`);
            }
            if(!syncing && !error) {
              // Dispatch confirmPickAction
              // 1. Flip the syncing state to true CONFIRM_PICK_START
              // 2. If there is an error stop everything and flip the error state to true CONFIRM_PICK_FAIL
              // 3. If everything goes well with the request, flip the syncing state to false and carry on CONFIRM_PICK_SUCCESS
                yield console.log(`this.props.confirmPickAction(${order.pickingListId});`);
            }
            // Dispatch removeConfirmedPickAction
            // This will remove the pick from sync queue (Redux state not API) after it has been confirmed
            console.log(`this.props.removeConfirmedPickAction();`);
          }
        }
      }
    }

    const SyncOrders = OrderIterator();

    for (const item of SyncOrders) {
        item;
    }

【问题讨论】:

    标签: react-native redux react-redux redux-saga


    【解决方案1】:

    这个怎么样:

    export const ordersToSync = state => state.ordersToSync;
    export const getLastSavedItemId = state => state.lastSavedItemId;
    export const getItemFailedOnConfirm = state => state.itemFailedOnCofirm;
    
    export function *syncDataIdea() {
      const ordersToSync = yield select(ordersToSync);
      for (const order of ordersToSync) {
        for (const item of order.itemsPicked) {
          yield call(updatePickQuantityAction, item.PickedQuantity);
        }
        yield call(confirmPickAction, order.pickingListId);
        yield call(removeConfirmedPickAction, order.pickingListId);
      }
    }
    
    export function *syncData() {
      const ordersToSync = yield select(ordersToSync);
      for (const order of ordersToSync) {
        const itemFailedOnConfirm = yield select(getItemFailedOnConfirm);
        if (itemFailedOnConfirm === null) {
          const lastSavedItemId = yield select(getLastSavedItemId);
          for (const item of order.itemsPicked) {
            const itemId = item.PickedQuantity.PickingListDetailId;
            try {
              if (lastSavedItemId !== null
                && lastSavedItemId !== itemId) {
                continue;
              }
              yield call(updatePickQuantityAction, item.PickedQuantity);
              yield put({type: 'SET_LAST_SAVED_ITEM', getLastSavedItemId: null});
            }
            catch (error) {
              yield put({
                type: 'SET_LAST_SAVED_ITEM', getLastSavedItemId: itemId
              });
            }
            finally {
              if (yield cancelled()) {
                yield put({
                  type: 'SET_LAST_SAVED_ITEM', getLastSavedItemId: itemId
                });
              }
            }
          }
        }
        try {
          yield call(confirmPickAction, order.pickingListId);
          yield put({type: 'ITEM_FAILED_ON_CONFIRM', pickingListId: null});
        }
        catch (error) {
          yield put({type: 'ITEM_FAILED_ON_CONFIRM', pickingListId: order.pickingListId});
        }
        finally {
          if (yield cancelled()) {
            yield put({type: 'ITEM_FAILED_ON_CONFIRM', pickingListId: order.pickingListId});
          }
        }
        yield call(removeConfirmedPickAction, order.pickingListId);
      }
    }
    
    function* main() {
      while (yield take('WIFI_ON')) {
        const syncDataTask = yield fork(syncData);
        yield take('WIFI_OFF');
        yield cancel(syncDataTask);
      }
    }
    

    请注意,我也是redux-saga 的新手。我建议你看看https://redux-saga.github.io/redux-saga/docs/advanced/TaskCancellation.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-26
      • 2017-07-07
      相关资源
      最近更新 更多