如何延迟Redux状态更改以允许React组件产生副作用

bdw*_*ain 3 reactjs redux react-redux

抱歉,标题模糊。解释我的问题的最好方法可能是一个例子。

我在redux中有一个项目,并且列表使用标准react-redux连接的组件显示在react组件中。每个单独的项目都有一个按钮,单击该按钮会执行一些异步工作,然后将其从列表中删除,并将其放在其他位置显示的另一个列表中。在redux中处理启动异步工作的逻辑很重要,因为它对我的应用程序的状态很重要。

该基本功能有效,但是现在我想向按钮添加反馈,以便当副作用成功时,它将标签更改为Checkmark(为简单起见,如果请求失败,我将不进行任何操作并保留列表不变)例)。该项目将被选中标记多停留一秒钟,然后再从列表中删除。

问题是,如果我在异步工作完成后立即从列表中删除该项目,则会立即将其卸载,因此我需要延迟该时间。我一直在尝试提出一种方法,以实现可在我的应用程序中重复使用的逻辑,因为我希望在应用程序的其他不相关部分中使用选中标记反馈。

一种简单的解决方案是在成功时调度一个操作,该操作仅更改状态以指示该项目的请求已成功,然后执行setTimeout在1秒后调度另一个操作以实际从列表中删除该项目。

我觉得如果我在有按钮的应用程序的不同位置执行此逻辑,它将变得非常重复。我希望不必为每个需要此按钮的按钮重复超时逻辑。但是我希望我的应用程序显示的内容代表我的应用程序的当前状态。

以前有没有人处理过这样的问题?

谢谢

编辑:我不认为它应该真正改变一般的解决方案,但我正在使用redux循环来处理副作用。我觉得通用解决方案可以与thunk或saga或其他任何东西一起很好地工作。

Ian*_*Ian 5

您提到您正在redux-loop用来处理异步内容。我比较熟悉redux-thunk,所以如果您满意,我会给您答案。

如果将超时置于动作创建者中,然后从多个按钮调用该动作创建者,则可以保持代码为DRY:

// actionCreators.js

const fetchTheThings = (url, successAction, failureAction, followUpAction) => (dispatch) => {

  //if you put the app in an intermediate state
  //while you wait for async, then do that here
  dispatch({ type: 'GETTING_THINGS' });

  //go do the async thing
  fetch(url)
    .then(res => {
      if (res.status === 200) return res.json();
      return Promise.reject(res);
    })
    .then(data => {
      //on success, dispatch an action, the type of which
      //you passed in as an argument:
      dispatch({ type: successAction, data });

      //then set your timeout and dispatch your follow-up action 1s later
      setTimeout(() => {
        dispatch({ type: followUpAction });
      }, 1000);
    })
    .catch(err => {
      //...and handle error cases
      dispatch({ type: failureAction, data: err });
    });
};

//then you can have exported action creators that your various buttons call
//which specify the action types that get passed into fetchTheThings()

export const actionFiredWhenButtonOneIsPressed = () => {
  return fetchTheThings('<some url>', '<success action>', '<failure action>', '<follow-up action>');
};

export const actionFiredWhenButtonTwoIsPressed = () => {
  return fetchTheThings('<other url>', '<other success action>', '<other failure action>', '<other follow-up action>');
};
Run Code Online (Sandbox Code Playgroud)

希望至少能给您一些想法。祝好运!