如何使用React + Redux重试承诺的API调用?

时间:2016-11-23 13:31:43

标签: javascript promise redux

我正在尝试实现以下内容:当API调用导致会话过期时,会弹出一个用户可以填写的模式登录表单。 重新登录后,重试原始请求并dispatch结果返回的原始承诺。

到目前为止,我在商店中有一个pendingActions列表和一个sessionExpired标志。该标志控制ModalLogin的挂载,可以调度retryPendingActions thunk。所以除了正确解决原始承诺之外,一切都有效:

this.props.dispatch(addItem(...)) // Either never resolves, or resolves too early
  .then(doStuffWithItem)
  .catch(handleUserErrors);

如果我可以在商店中保存承诺,我可以避免在会话过期上解决它,而是在retryPendingActions期间解决它。但是,我已经阅读了很多问题和官方文档,这是一个坏主意。

我是以错误的方式来做这件事的吗?有没有更好的方法来处理这种情况?

2 个答案:

答案 0 :(得分:0)

不确定这是否是最好的答案,但我能够找到答案。它有点hackish,但涉及将subscribe方法放入thunk:

const store = createStore(
    rootReducer, 
    defaultState,
    applyMiddleware(ReduxThunk.withExtraArgument((...args) => store.subscribe(...args)))
);

从那时起,它就是在正确的时间解决承诺:

function retryWhileNotLoggedIn(fetcher, dispatch, getState, subscribe) {
    let resolve, reject, unsubscribe;
    const ret = new Promise((res, rej) => {
        resolve = res;
        reject = rej;
    });

    const attempt = () => fetcher()
        .then(resolve, err => {
            if (err && err.status === 403) {
                unsubscribe = subscribe(onStoreChange);
                dispatch(actions.setSessionExpired(true));
            } else {
                reject(err);
            }
        });

    function onStoreChange() {
        if (getState().sessionValid) { // Other checks possible
            unsubscribe();
            attempt();
        }
    }

    attempt();
    return ret;
}

使用retryWhileNotLoggedIn,包装API本身非常简单:

function getItem(item, metadata={}) {
    return function thunk(dispatch, getState, subscribe) {
        dispatch(actions.startCall("getItem", metadata));

        return retryWhileNotLoggedIn(() => api.getItem(item), dispatch, getState, subscribe)
            .then(res => {
                dispatch(actions.endCall("getItem", metadata));
                return res;
            }, err => {dispatch(actions.endCall("getItem"), metadata); throw err;});
    };
}

完整实现还有一个额外的检查,以查看登录用户或活动路由是否更改,在这种情况下,承诺未解决。这种方法的一个缺点是挂起的操作不再存储在商店中,而是隐藏在最终归api模块所拥有的一系列闭包中

答案 1 :(得分:0)

另一个选择是使用redux-observable

Here是angular2

的示例