使用Fetch API和Promise React Redux Action Creator Dispatch问题

时间:2018-04-24 05:34:26

标签: react-redux

我正在反应应用程序中编写动作创建者。当我做一些api调用时,我需要在屏幕上显示Progress Loader。所以,我的动作创建者看起来像这样。

export const fetchData = (actionType, param) => (dispatch) => {
  dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER)); // Show Loader Action
  return fetchDataRequest(actionType, param) // Here is Fetch APi Call
    .then(responseData => {
      dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER));
      dispatch(Action(recd(actionType), { data: responseData, receivedAt: Date.now() }));
    }).catch((error) => {
      dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
    });
};

当我编写这段代码时,它正如预期的那样工作,我将动作作为dispatch(fetchData(data))从组件调度,我能够在我的父组件中显示加载器。我理解的是fetch正在回报我的承诺。一旦fetch完成,我就会隐藏正在按预期工作的加载器。

现在,有一种情况我需要做一些验证,我不需要进行任何api调用,但所有验证都是在本地执行的。 在这里我也想做同样的事情,就像我需要在我的父组件中显示加载器以及完成所有验证后我需要隐藏加载器。 我已经编写了相同的代码片段甚至动作被调用但我的渲染函数没有被调用。 我的代码看起来像:

// This my action creator which will actually do the validation
export const validateAndSaveData = () => {
  return ((dispatch, getState) => {
    return new Promise((resolve, reject) => {
      let saveRecommendDetailsFlag = true;
      // here i am dispacthing some action and storing data in my store
      saveRecommendDetailsFlag = canSaveData(getState());
      if (saveRecommendDetailsFlag) {
        resolve('SUCCESS');
      } else {
        reject('ERROR');
      }
    });
  });
};

还有一个动作创建者,我从UI组件中调用它,它将首先启动show loader动作然后执行验证,并根据验证结果我必须隐藏加载器。

export const saveData = () => {
  return ((dispatch) => {
   dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER)); // Show Loader Action
    return dispatch(validateAndSaveData())
      .then(() => {
       // Here i m dispatching an action to do some more processing.
 dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
      })
      .catch(() => {
       dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
      });
  });
};

一切正常,但我的装载机没有进入屏幕。我无法弄明白我在哪里做错了。

有人可以提出建议,我该如何解决这个问题? 我使用setTimeout func得到了一些解决方法,但我不认为这是正确的方法。

export const saveData = () => {
  return ((dispatch) => {
   dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER)); // Show Loader Action
    setTimeout(()=>return dispatch(validateAndSaveData())
      .then(() => {
       // Here i m dispatching an action to do some more processing.
 dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
      })
      .catch(() => {
       dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
      });
},10);
  });
};

1 个答案:

答案 0 :(得分:0)

您的代码看起来很合理,我怀疑您的validateAndSaveData承诺如此快速地完成,以至于屏幕上没有可见的加载程序。

在这种情况下,超时是完全合理的。但是,为了正确地做到这一点,如果加载屏幕可见+如果显示的时间足够长,我会保持状态。然后,您可以在加载屏幕足够长时间后移除加载屏幕,并且实际事件将过期。

我不确定你正在使用哪个动作包,所以我无法发布确切的代码,但伪代码看起来像这样:

const delay = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds));


let loadingCounter = 0;
const showLoadingScreen = () => (dispatch) => {
  const counter = loadingCounter;
  loadingCounter++;

  delay(5).then(() => {
    if (getStore().loadingScreen.counter === counter) {
      dispatch(Action(ActionConstants.PROGRESS_LOADER_DELAY_ELAPSED))
    }
  })

  return dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER, counter))
}

基本上,你会跟踪装载机的3个状态:

{
  counter: 0,
  taskCompleted: false,
  canHide: false,
}

保存计数器,以便您可以消除在现有SHOW_PROGRESS_LOADER正在进行时获得SHOW_PROGRESS_LOADER时发生的情况。 taskCompleted会记录您正在等待的事情是否已完成,并且canHide会跟踪加载程序是否已在屏幕上显示足够长的时间。

当你发送PROGRESS_LOADER_DELAY_ELAPSED时,它将canHide设置为true,当你发送HIDE_PROGRESS_LOADER时,它将taskCompleted设置为true。 (尽管您可能希望重命名后一个操作)。当canHidetaskCompleted都设置为true时,加载程序才会消失。

这是一种非常常见的UI模式 - 尝试快速完成任务。如果花费的时间超过很短的时间,则抛出一个加载对话框。但是,加载对话框可以保持最短的时间以防止闪烁。因此,这种模式的更高级版本将添加另一个根本不显示进度加载器的状态,除非调用超过Y毫秒。

希望这是有道理的,如果没有,请留下评论: - )