【问题标题】:Async does wait for data to be returned in a redux-thunk function异步确实等待数据在 redux-thunk 函数中返回
【发布时间】:2021-05-17 04:46:18
【问题描述】:

我正在尝试使用来自我的 mongo-db 领域数据库的数据填充我的 redux 存储。 每当我运行下面的函数时,它都会执行良好,但问题是数据会延迟并且最终无法到达我的 redux 存储。

我的thunk函数:

export const addItemsTest = createAsyncThunk(
  "addItems",
  async (config: any) => {
    try {
      return await Realm.open(config).then(async (projectRealm) => {
        let syncItems = await projectRealm.objects("Item");
        await syncItems.addListener((x, changes) => {
          x.map(async (b) => {
            console.log(b);
            return b;
          });
        });
      });
    } catch (error) {
      console.log(error);
      throw error;
    }
  }
);

还有我的 redux reducer:

  extraReducers: (builder) => {
      builder.addCase(addItemsTest.fulfilled, (state, { payload }: any) => {
        try {
          console.log("from add Items");
          console.log(payload);
          state.push(payload);
        } catch (error) {
            console.log(error)
         }
      });
  }

预期结果: 我的 redux 商店应该有这些数据一次 addItemsTest 返回一些东西:

[{
itemCode: 1,
itemDescription: 'Soccer Ball',
itemPrice: '35',
partition: 'partitionValue',
},
{
itemCode: 2,
itemDescription: 'Base Ball',
itemPrice: '60',
partition: 'partitionValue',
}
]

实际结果:

【问题讨论】:

    标签: javascript typescript react-native redux redux-thunk


    【解决方案1】:

    混合语法

    您正在以一种非常混乱的方式组合 await/asyncPromise.then() 语法。混合这两种语法不是错误,但我不建议这样做。坚持await/async

    无效回归

    您的操作现在实际上没有返回任何值,因为您的内部 then 函数没有返回任何值。唯一的returnthen 内部,在x.map 回调中。 await syncItems 是映射器的返回值,而不是你的函数。

    现在,这是您的 thunk 所做的:

    • 打开连接
    • 从领域获取物品
    • 为记录更改的项目添加监听器
    • 返回解析为voidPromise

    解决方案

    我相信你想要的是这样的:

    export const addItemsTest = createAsyncThunk(
      "addItems",
      async (config: any) => {
        try {
          const projectRealm = await Realm.open(config);
          const syncItems = await projectRealm.objects("Item");
          console.log(syncItems);
          return syncItems;
        } catch (error) {
          console.log(error);
          throw error;
        }
      }
    );
    

    没有日志记录,可以简化为:

    export const addItemsTest = createAsyncThunk(
      "addItems",
      async (config: any) => {
        const projectRealm = await Realm.open(config);
        return await projectRealm.objects("Item");
      }
    );
    

    您不需要catch 错误,因为createAsyncThunk 将通过调度错误操作来处理错误。

    编辑:聆听变化

    您的意图似乎是将您的 redux 存储与您的 Realm 集合中的更改同步。因此,您希望向调用 dispatch 的集合添加一个侦听器,并通过一些操作来处理更改。

    在这里,我假设此操作需要一个包含您集合中所有项目的数组。像这样的:

    const processItems = createAction("processItems", (items: Item[]) => ({
      payload: items
    }));
    

    替换您所在州的整个数组是最简单的方法。当您将项目对象替换为相同版本时,这会导致一些不必要的重新渲染,但这没什么大不了的。

    或者,您可以传递changes 的特定属性,例如insertions,并根据具体情况在减速器中处理它们。

    为了添加一个分发processItems 的监听器,我们需要访问两个变量:领域config 和redux dispatch。您可以在您的组件中执行此操作,也可以通过调用“init”操作来执行此操作。我不认为有太大的区别。如果你愿意,你可以在你的 reducer 中做一些事情来响应“init”动作。

    这是一个添加监听器的函数。 Realm.Results 对象是“类数组”但不完全是数组,因此我们使用 [...x] 将其转换为数组。

    仅供参考,此函数可能会引发错误。如果在createAsyncThunk 中使用这很好,但在组件中我们希望catch 那些错误。

    const loadCollection = async (config: Realm.Configuration, dispatch: Dispatch): Promise<void> => {
      const projectRealm = await Realm.open(config);
      const collection = await projectRealm.objects<Item>("Item");
      collection.addListener((x, changes) => {
        dispatch(processItems([...x]));
      });
    }
    

    通过中间 addListener 动作创建者添加侦听器:

    export const addListener = createAsyncThunk(
      "init",
      async (config: Realm.Configuration, { dispatch }) => {
        return await loadCollection(config, dispatch);
      }
    );
    
    // is config a prop or an imported global variable?
    const InitComponent = ({config}: {config: Realm.Configuration}) => {
      const dispatch = useDispatch();
    
      useEffect( () => {
        dispatch(addListener(config));
      }, [config, dispatch]);
    
      /* ... */
    }
    

    直接添加监听器:

    const EffectComponent = ({config}: {config: Realm.Configuration}) => {
      const dispatch = useDispatch();
    
      useEffect( () => {
        // async action in a useEffect need to be defined and then called
        const addListener = async () => {
          try {
            loadCollection(config, dispatch);
          } catch (e) {
            console.error(e);
          }
        }
    
        addListener();
        
      }, [config, dispatch]);
    
      /* ... */
    }
    

    【讨论】:

    • 很抱歉我写错了代码,请您在修改后重读一遍
    • 同样的问题。你仍然没有返回任何东西。
    • 似乎他正在尝试一个监听器来监听他的数据库上的更改,然后如果有人从不同的设备进行更改,则添加任何项目
    • 我正在监听数据库的变化,实际上需要运行这个函数await syncItems.addListener
    • @Fanyana 这是有道理的。我真的不明白添加监听器以响应动作的目的。似乎这里需要的是添加一个调度动作的侦听器。监听器的添加可以与动作创建者完全分开。
    猜你喜欢
    • 2023-03-23
    • 2019-04-18
    • 2019-03-02
    • 2017-06-15
    • 2013-07-24
    • 2011-03-04
    • 1970-01-01
    • 2021-05-25
    • 2019-08-03
    相关资源
    最近更新 更多