Redux-Thunk - Обещание создателей асинхронных действий и цепочка не работают

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

Не могли бы вы дать мне подсказку? Что я делаю не так?

Я использую TypeScript и недавно удалил все типы и максимально упростил свой код.

Я использую redux-thunk и redux-promise, например:

import { save } from 'redux-localstorage-simple';
import thunkMiddleware from 'redux-thunk';
import promiseMiddleware from 'redux-promise';

const middlewares = [
        save(),
        thunkMiddleware,
        promiseMiddleware,
    ];
const store = createStore(
        rootReducer(appReducer),
        initialState,
        compose(
            applyMiddleware(...middlewares),
            window['__REDUX_DEVTOOLS_EXTENSION__'] ? window['__REDUX_DEVTOOLS_EXTENSION__']() : f => f,
        ),
    );

Компонент — компонент Foo:

import actionFoo from 'js/actions/actionFoo';
import React, { Component } from 'react';
import { connect } from 'react-redux';

class Foo {
    constructor(props) {
        super(props);
        this._handleSubmit = this._handleSubmit.bind(this);
    }
    _handleSubmit(e) {
        e.preventDefault();
        this.props.doActionFoo().then(() => {
            // this.props.doActionFoo returns undefined
        });
    }
    render() {
        return <div onClick={this._handleSubmit}/>;
    }
}

const mapStateToProps = ({}) => ({});

const mapDispatchToProps = {
    doActionFoo: actionFoo,
};

export { Foo as PureComponent };
export default connect(mapStateToProps, mapDispatchToProps)(Foo);

Действие – actionFoo:

export default () => authCall({
    types: ['REQUEST', 'SUCCESS', 'FAILURE'],
    endpoint: `/route/foo/bar`,
    method: 'POST',
    shouldFetch: state => true,
    body: {},
});

Действие – AuthCall:

// extremly simplified
export default (options) => (dispatch, getState) => dispatch(apiCall(options));

Действие – ApiCall:

export default (options) => (dispatch, getState) => {
    const { endpoint, shouldFetch, types } = options;

    if (shouldFetch && !shouldFetch(getState())) return Promise.resolve();

    let response;
    let payload;

    dispatch({
        type: types[0],
    });

    return fetch(endpoint, options)
        .then((res) => {
            response = res;
            return res.json();
        })
        .then((json) => {
            payload = json;

            if (response.ok) {
                return dispatch({
                    response,
                    type: types[1],
                });
            }
            return dispatch({
                response,
                type: types[2],
            });
        })
        .catch(err => dispatch({
            response,
            type: types[2],
        }));
};

person dazlious    schedule 04.01.2018    source источник
comment
что возвращает console.log(res.json())?   -  person lfender6445    schedule 05.01.2018
comment
Это обещание. Решенный   -  person dazlious    schedule 05.01.2018
comment
Ваш отладчик сообщает вам, какой then вызывается на undefined?   -  person Joshua R.    schedule 05.01.2018
comment
Прошло некоторое время с тех пор, как я использовал редукционный преобразователь, и я не уверен, но я предполагаю, что actionFoo должен возвращать диспетчерский вызов вместо прямого вызова действия authCall. Возможно, этот пример (который был написан давно) может вам помочь: github.com/svenvandescheur /react-redux-consumerjs-пример   -  person Sven van de Scheur    schedule 05.01.2018
comment
@ДжошуаР. Конечно, один: this.props.doActionFoo(gameName, password).then() Я прокомментировал код выше.   -  person dazlious    schedule 05.01.2018
comment
У вас есть redux-promise? redux-thunk не обрабатывает обещания   -  person The Reason    schedule 05.01.2018
comment
@SvenvandeScheur: Нет, потому что выше приведена краткая форма: const mapDispatchToProps = dispatch =› { return { doActionFoo: () =› dispatch(actionFoo()), }; };   -  person dazlious    schedule 05.01.2018
comment
@TheReason: я думал, что redux-thunk справится с этим за меня: github.com/gaearon/redux- thunk#композиция   -  person dazlious    schedule 05.01.2018
comment
@ShubhamKhatri: мне не нужно пробовать это, потому что стрелочные функции автоматически возвращают следующий оператор, если область действия блока не начинается   -  person dazlious    schedule 08.01.2018
comment
AuthCall возвращает отправку, которая не возвращает обещание. Я не понимаю, почему AuthCall должен вызывать dispatch() с вложенным ApiCall внутри, если ApiCall вызывает диспетчеризацию   -  person Eric Hasselbring    schedule 09.01.2018


Ответы (2)


Из redux-thunk

Промежуточное ПО Redux Thunk позволяет вам писать создателей действий, которые возвращают функцию вместо действия.

Так что это означает, что он не справляется с вашими обещаниями. Вы должны добавить redux-promise для поддержки промисов

Экспорт по умолчанию — это промежуточная функция. Если он получает промис, он отправит разрешенное значение промиса. Он ничего не отправит, если обещание отклонено.

Различия между redux-thunk и redux-promise вы можете прочитать здесь

person The Reason    schedule 05.01.2018
comment
Можете ли вы привести пример того, как добавить это в мой существующий код, или мне нужно добавить это только в промежуточное ПО? - person dazlious; 05.01.2018
comment
@dazlious просто добавьте его в промежуточное ПО - person The Reason; 05.01.2018
comment
До или после добавления thunk? - person dazlious; 05.01.2018
comment
у вас есть рабочий пример с подключением и mapDispatchToProps? Я не могу заставить это работать - person dazlious; 05.01.2018
comment
Хорошо, тогда что я делаю не так? :( Это расстраивает ;) - person dazlious; 05.01.2018
comment
Давайте продолжим обсуждение в чате. - person The Reason; 05.01.2018

Хорошо, через несколько часов я нашел решение. redux-thunk должен был быть первым перед любым другим промежуточным программным обеспечением. Поскольку промежуточное ПО вызывается справа налево, возврат редукционного перехода является последним в цепочке и, следовательно, возвращает обещание.

import thunkMiddleware from 'redux-thunk';

const middlewares = [
        thunkMiddleware,
        // ANY OTHER MIDDLEWARE,
    ];
const store = createStore(
        rootReducer(appReducer),
        initialState,
        compose(
            applyMiddleware(...middlewares),
            window['__REDUX_DEVTOOLS_EXTENSION__'] ? window['__REDUX_DEVTOOLS_EXTENSION__']() : f => f,
        ),
    );
person dazlious    schedule 08.01.2018