Как мне решить "Действия должны быть простыми объектами. Использовать пользовательское промежуточное ПО для асинхронных действий.]"?

Так что я потратил 5 часов на это.

У меня есть редукция Thunk, как это:

export const fetchUser = () => async (getState, dispatch) => {
  if (getIsFetching(getState().user)) {
    return Promise.resolve();
  }

  dispatch(fetchUserRequest());

  try {
    const response = await api.fetchUser();

    dispatch(fetchUserSuccess({ userObject: { ...response } }));
  } catch (error) {
    dispatch(fetchUserFailure({ message: "Could not fetch user profile." }));
  }
};

Вызов этого всегда заканчивался в "Действия должны быть простыми объектами. Используйте пользовательское промежуточное программное обеспечение для асинхронных действий.]".

Да, конечно. Я уже использую Redux-Thunk для этого, почему он продолжает беспокоить меня?

ПРИМЕЧАНИЕ: fetchUserRequest(), fetchUserSuccess() и fetchUserFailure() все возвращают простые, простые редукционные действия.

1 ответ

Решение
export const fetchUser = () => async (getState, dispatch) => {// your code here}

должно быть

export const fetchUser = () => async (dispatch, getState) => {// your code here}

(getState, dispatch)! == (dispatch, getState)

Хотя я рад, что в конце концов решил эту проблему, путь был довольно разочаровывающим.

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

В действительности, с вашим создателем действий есть две ошибки. Первое, что не так с вашим создателем действий, это то, что ваш создатель действий должен возвращать простые объекты JavaScript с type собственность и, возможно, payload собственность, но в настоящее время вы не возвращаете действие от создателя действия.

Вы можете посмотреть на свой редактор кода и посмотреть на создателя действия, и вы можете подумать: вы смотрите на того же создателя действия, что и я? Может показаться, что вы возвращаете объект с type собственности, но на самом деле вы не.

Хотя похоже, что вы возвращаете объект JavaScript, это не так.

Большая часть кода, который мы пишем в нашем редакторе, написана на ES2015, 2016, 2017, 2018 и так далее. Код, который мы с вами пишем, передается в синтаксис es2015, и это то, что фактически выполняется внутри браузера.

Так что, хотя эта функция выглядит как возвращающая объект с type собственно, после того, как мы перенесем это в код es2015, мы не являемся.

В следующий раз добавьте создателя асинхронных действий в babeljs.io, и вы поймете, что я имею в виду.

Это то, что фактически переносит наш код в ES2015.

Так что внутри редактора кода вы думаете, что выполняете написанный код, но на самом деле, поскольку у вас есть этот синтаксис async/await, вся функция расширяется до того, что вы видите в правой части babeljs.io.

Поэтому, когда я говорю вам, что создатель ваших действий не возвращает простой объект JavaScript, это происходит потому, что у вас есть этот синтаксис async/await. Вот почему ваш создатель действий не работает, как ожидалось.

Таким образом, вы возвращаете, а не объект действия, когда он первоначально вызывается. Поэтому, когда ваш создатель действия вызывается в первый раз, вы не возвращаете объект действия, вместо этого, как вы видели, у вас есть некоторый код внутри, который возвращает ваш объект запроса. Так вот что получает возвращенный запрос. Таким образом, вы возвращаете запрос от вашего создателя действия, и это идет в store.dispatch метод.

Затем хранилище избыточности смотрит на то, что было возвращено, и говорит, хорошо, это простой объект JaavaScript только с type имущество? Ну, в данном случае, нет, потому что мы просто вернули объект запроса, мы не вернули наше действие, и поэтому мы в конечном итоге увидели неприятное красное сообщение о том, что Действия должны быть простыми объектами. Таким образом, мы не вернули простой объект, а действия должны вернуть простые объекты. Мы возвратили объект запроса, которому, вероятно, назначены некоторые причудливые методы, и, вероятно, type собственность, поэтому мы определенно не отправили то, что мы думали, что отправляли.

Это все из-за синтаксиса async/await, который вы используете.

Так что это проблема номер 1 с вашим создателем действий. В результате использования синтаксиса async/await, который передается в код es5, то, что на самом деле работает внутри вашего браузера, не то, что вы думаете, на самом деле работает.

Таким образом, мы отправляем действие NOT Redux, мы отправляем случайный объект, который не волнует Redux.

Так как же нам правильно использовать это промежуточное ПО под названием Redux-Thunk? Прежде чем ответить на этот вопрос, давайте разберемся, что такое промежуточное ПО в мире Redux.

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

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

Итак, как Redux-Thunk помогает нам решить эту проблему?

Что ж, Redux-Thunk ослабит обычные правила создателя действий или Redux, который говорит, как я уже говорил выше, что создатель действий должен возвращать объекты действий, он должен иметь type собственность и, необязательно, payload имущество.

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

Как только в нашем создателе действий задействован Redux-Thunk, он может возвращать простые объекты ИЛИ может возвращать функции.

Вы видите, куда это идет?

Так как же может помочь возврат функции?

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

Redux-Thunk скажет: "Привет, ты функция или объект?" Если "действие" сообщает Redux-Thunk, что это объект, Redux-Thunk скажет: "Хорошо, спасибо, что остановились на действии, но я предпочитаю иметь дело только с функциями", а затем Redux-Thunk переместит "действие" в сторону редукторы.

В противном случае Redux-Thunk скажет: "О, так что вы - функция? Redux-Thunk затем вызовет вашу функцию и передаст dispatch, getState функции в качестве аргументов. Вам уже дали синтаксическую версию вашего ответа, поэтому позвольте мне предложить ее вариант.

Так что вместо этого:

export const fetchPosts = async () => {
  const response  = await jsonPlaceholder.get('/posts');
  return {
      type: 'FETCH_POSTS',
      payload: response
  }
};

с Redux-Thunk вы бы включили это:

export const fetchPosts = async () => {
  return function(dispatch, getState) {
    const response  = await jsonPlaceholder.get('/posts');
    return {
        type: 'FETCH_POSTS',
        payload: response
    }
  }
};

Теперь в приведенном выше примере я делаю асинхронный запрос с моим создателем действия на внешний API. Так это dispatch имеет неограниченные полномочия изменять данные на стороне Redux нашего приложения.

Вы видите, что я использую getState так что вы также можете понять, что в дополнение к dispatch, getState вернет все данные внутри вашего магазина. Эти два аргумента имеют неограниченную силу внутри нашего приложения Redux. Через dispatch мы можем изменить любые данные, которые мы хотим, и через getState мы можем прочитать любые данные, которые мы хотим.

Перейдите к исходному коду самого Redux-Thunk: https://github.com/reduxjs/redux-thunk/blob/master/src/index.js

Выше все из Redux-Thunk. Только 6-7 строк делают что-либо, остальные - этапы инициализации, объявления функций и экспорт. В строке 2 находится ряд функций, которые возвращают функции.

В его теле вы видите логику происходящего и спрашиваете, отправляете ли вы и действие, и если да, то это действие или функция?

Все, что я описал выше, записано в исходном коде.

Поэтому для того, чтобы я правильно применил Redux-Thunk к приведенному мною примеру, я бы пошел в свой корень index.js файл и импорт после установки его в терминале так:

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunk from 'redux-thunk';

import App from "./components/App";
import reducers from "./reducers";

ReactDOM.render(
  <Provider store={createStore(reducers)}>
    <App />
  </Provider>,
  document.querySelector("#root")

Обратите внимание, я также импортировал applyMiddleware, Эта функция - то, как мы подключаем промежуточное ПО к Redux.

Итак, я применяю createStore вперед в переменную под названием store и реализовать это внутри хранилища провайдеров следующим образом:

const store = createStore(reducers);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.querySelector("#root")
);

Чтобы подключить Redux-Thunk, в качестве второго аргумента я назову applyMiddleware и пройти в thunk вот так:

const store = createStore(reducers, applyMiddleware(thunk));

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.querySelector("#root")

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

Поэтому вместо того, чтобы возвращать действие, я могу позвонить dispatch и передать в мой объект действия, например, так:

export const fetchPosts = () => {
  return async function(dispatch, getState) {
    const response  = await jsonPlaceholder.get('/posts');

    dispatch({type: 'FETCH_POSTS', payload: response })
  }
};

С Redux-Thunk мы можем использовать синтаксис async/await, потому что этот синтаксис только изменит возвращаемое значение внутренней функции. Ничто из функции никогда не привыкнет. Redux-Thunk не будет получать ссылку на то, что возвращается, и использовать ее, мы можем возвращать или не возвращать, это то, что мы возвращаем из нашей внешней функции, это то, что нас волнует.

Общий способ рефакторинга того, что я только что поделился выше, выглядит так:

export const fetchPosts = () => {return async (dispatch) => {const response = await jsonPlaceholder.get ('/ posts');

dispatch({type: 'FETCH_POSTS', payload: })

}};

Так что, если вы не используете getState внутри функции вы можете оставить это в качестве аргумента. Вы можете сделать свой код еще более лаконичным, например, так:

export const fetchPosts = () => async dispatch => {
    const response  = await jsonPlaceholder.get('/posts');

    dispatch({type: 'FETCH_POSTS', payload: response })
} 

Вы увидите это во многих проектах Redux. Это оно.

Другие вопросы по тегам