Как связать действия с промежуточным программным обеспечением Redux Promise?

Я довольно новичок в React и Redux. Я хочу объединить несколько вызовов API с использованием redux-обещания-промежуточного программного обеспечения и реализовал свои действия следующим образом:

locationActions.js:

import { visitLocation } from '../services/actionService';

export const VISIT_LOCATION = 'VISIT_LOCATION';
export const VISIT_LOCATION_PENDING = 'VISIT_LOCATION_PENDING';
export const VISIT_LOCATION_FULFILLED = 'VISIT_LOCATION_FULFILLED';
export const VISIT_LOCATION_REJECTED = 'VISIT_LOCATION_REJECTED';

const visitLocationAction = (characterId, location) => ({
    type: VISIT_LOCATION,
    // visitLocation returns a new promise
    payload: visitLocation(characterId, location)
});

export { visitLocationAction as visitLocation };

Я отправляю это действие из моего компонента React, используя mapDispatchToProps:

const mapDispatchToProps = dispatch => (
    bindActionCreators({ visitLocation }, dispatch)
);

Это работает! Тем не менее, я хочу отправить еще одно действие после visitLocation улажено и выполнено. Я не могу позвонить Promise.then() потому что это не обеспечивает dispatch метод, поэтому не "привязывать" мои действия к редуктору.

Учебники упоминают, что я должен позвонить dispatch(secondAction()) но у меня нет доступных отправителей в моих действиях создателей.

Может кто-нибудь указать мне, что я скучаю?

Редактировать:

Как предложено в первом ответе, я попробовал следующий подход:

import { visitLocation } from '../services/locationService';
import { fetchSomething } from '../services/otherService';

const visitLocationAction = (characterId, location) => {
    return (dispatch) => {
        return dispatch(visitLocation(characterId, location))
            .then(() => dispatch(fetchSomething()));
    };
};

export { visitLocationAction as visitLocation };

Но я получил action: undefined и следующую ошибку:

Error: Actions must be plain objects. Use custom middleware for async actions.
    at dispatch (redux.js:200)
    at redux-logger.js:1

2 ответа

Решение

Учебники упоминают, что я должен позвонить dispatch(secondAction()) но у меня нет доступных отправителей в моих действиях создателей.

Позвольте мне сначала ответить на эту часть вашего вопроса. Как уже упоминалось в первом ответе, вам нужно Redux Thunk, промежуточное программное обеспечение, чтобы использовать dispatch в твоих действиях создатели.

По умолчанию создатели действий Redux возвращают простые объекты, например:

const returnsAnObject = () => ({
  type: 'MY_ACTION'
  payload: ...,
  meta: ....
})

С Redux Thunk создатели действий могут по существу возвращать функции. Функция, которая возвращает функцию, называется "thunk", отсюда и название Redux Thunk.

const returnsAFunction = (dispatch) => dispatch({
  type: 'MY_ACTION'
  payload: ...,
  meta: ....
})

В конкретном случае Redux Thunk вы возвращаете dispatch функция. Redux Thunk позволяет вам вернуться dispatch предоставляя его в качестве параметра для ваших создателей действий.

Но я получил action:undefined

Давайте распакуем это. Мы знаем - благодаря Redux Thunk- вы можете связать несколько действий вместе, используя dispatch, Однако, как вы упомянули в отредактированном вопросе, вы все равно получаете ошибку "простой объект".

Error: Actions must be plain objects. Use custom middleware for async actions.
    at dispatch (redux.js:200)
    at redux-logger.js:1

Это потому что ты звонил dispatch с объектом Promise, а не простым объектом.

const visitLocationAction = (characterId, location) => {
    return (dispatch) => {
        return dispatch(visitLocation(characterId, location))

            // Yes, it is correct to call dispatch here
            // However, `dispatch` accepts plain objects, not Promise objects
            .then(() => dispatch(fetchSomething()));
    };
};

Чтобы решить эту проблему, просто измените вашу вторую отправку, чтобы использовать простой объект:

const visitLocationAction = (characterId, location) => {
    return (dispatch) => {
        return dispatch(visitLocation(characterId, location))
            .then(() => dispatch({{
                type: 'VISIT_LOCATION_SECOND_TIME'
                payload: fetchSomething()
            }));
    };
};

Как упомянуто в документации по промежуточному программному обеспечению redux -обещания, промежуточное программное обеспечение может быть объединено с Redux Thunk для создания цепочки действий создателей.

Таким образом, вы можете написать свое действие как:

const secondAction = (data) => ({
  type: 'SECOND',
  payload: {...},
})

const thirdAction = (data) => ({
  type: 'THIRD',
  payload: {...},
})

const firstAction = () => {
  return (dispatch) => {
    return visitLocation(characterId, location)
      .then((data) => dispatch(secondAction(data)))
      .then((data) => dispatch(thirdAction(data)))
  }
}

или используйте async/await

const secondAction = (data) => ({
      type: 'SECOND',
      payload: {...},
    })

    const thirdAction = (data) => ({
      type: 'THIRD',
      payload: {...},
    })

    const firstAction = async () => {
      return (dispatch) => {
        const data = await visitLocation(characterId, location));
        dispatch(secondAction(data))
        dispatch(thirdAction(data))
      }
    }

и затем используйте его, как вы упомянули:

const mapDispatchToProps = dispatch => (
  bindActionCreators({ firstAction }, dispatch)
);
Другие вопросы по тегам