首页 > 解决方案 > Redux Saga:登录按钮的加载指示器

问题描述

我们使用以下 saga 通过电话注册用户:

function* signup() {
    while (true) {
        const {phone} = yield take("APP_SIGNUP");

        nav.toCode();

        const responseSignup = yield call(fetch.signUp, phone);

        if (!responseSignup.success) {
            yield put({type: "SIGNUP_SERVER_ERROR"}); 
            continue;
        }

        let i;

        for (i = 0; i < 3; i++) {
            const {code} = yield take("APP_CHECK_CODE");

            // MARKED LINE
            const {success} = yield call(fetch.checkCode, {
                phone,
                code,
            });

            if (success) break;
            yield put({ type: "APP_CHECK_CODE_WRONG" });
       }

    // code ok
    if (i < 3) {
        nav.toTabs();
        yield put({ type: "APP_CHECK_USER" });
    }
 ...

用户输入他的电话号码并显示一个屏幕,他在其中填写 4 位代码 - 你知道演习。

我们想添加一个加载指示器。有没有办法向调用 APP_CHECK_CODE 操作的人返回承诺*?

*在代码中标有“MARKED LINE”

标签: redux-sagasaga

解决方案


你可以从 thunk 中返回一个 Promise,但是如果你想坚持使用 saga,除了更改 redux 存储状态之外,没有简单的方法可以让调度操作的组件知道 saga 已完成。

所以我解决这个问题的方法是使用减速器,例如:

export (state = {checkingCode: false}, action) => {
    switch (action.type) {
        case APP_CHECK_CODE:
            return {...state, checkingCode: true};
        case APP_CHECK_CODE_WRONG:
        case APP_CHECK_CODE_SUCCESS:
            return {...state, checkingCode: false};
        default:
            return state;
    }
}

然后根据checkingCode值显示/隐藏加载指示器。

从理论上讲,如果您真的想将状态保留在组件本身中,您可以将诸如观察者之类的东西传递给 saga,然后等待它。

// component
const observable = Observable.create(observer => {
    this.setState({loading: true});
    dispatch({type: APP_CHECK_CODE, observer});
});
observable.subscribe({
  complete: () => this.setState({loading: false}),
});


// saga
const {code, observer} = yield take("APP_CHECK_CODE")
...
observer.complete();

但老实说,这感觉很神奇,而且会导致比它的价值更多的麻烦。


推荐阅读