Redux Saga: индикатор загрузки для кнопки входа - PullRequest
0 голосов
/ 21 декабря 2018

Мы используем следующую сагу, чтобы зарегистрировать пользователя по телефону:

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"

1 Ответ

0 голосов
/ 21 декабря 2018

Вы можете вернуть обещание из thunk, но если вы хотите придерживаться саг, нет простого способа сообщить компоненту, отправившему действие, о завершении саги, кроме изменения состояния хранилища с избыточностью.

Таким образом, я бы хотел обойти это, используя редуктор, такой как:

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.

Теоретически, вы можете передать что-то вроде наблюдателя в сагу, а затем ждать этого, если вы действительно хотите сохранить состояние в самом компоненте.

// 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();

Но, честно говоря, это кажется очень волшебным и может привести к большим неприятностям, чем стоит.

...