如何解决“动作必须是普通对象。将自定义中间件用于异步动作。]”?

mfr*_*fru 3 redux-thunk

因此,我在此上浪费了5个小时。

我有一个redux 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." }));
  }
};
Run Code Online (Sandbox Code Playgroud)

调用它总是结束于“操作必须是普通对象。将自定义中间件用于异步操作。]”。

好,当然。我已经在使用redux-thunk了,为什么它一直困扰着我?

注意:fetchUserRequest(),fetchUserSuccess()和fetchUserFailure()都返回简单的普通redux操作。

Dan*_*iel 16

了解此错误消息是了解Redux世界中许多内容的关键。这甚至可能是您将来会问的面试问题。

实际上,您的动作创建者有两件事是错误的。动作创建者的第一件事是,您的动作创建者应该返回带有type属性和可选payload属性的普通JavaScript对象,但是目前您还没有从动作创建者返回动作。

您可能会看代码编辑器,然后看动作创建器,然后您可能会想,您是否在寻找与我相同的动作创建器?看起来您正在返回具有type属性的对象,但实际上您没有。

即使看起来您正在返回一个JavaScript对象,事实并非如此。

我们在编辑器中编写的许多代码是ES2015、2016、2017、2018等。您和我编写的代码都将转换为es2015语法,这就是在浏览器中实际执行的代码。

因此,即使此函数看起来像返回具有type属性的对象,实际上,在将其转换为es2015代码后,我们却没有。

下次将您的异步操作创建者放到babeljs.io中,您将明白我的意思。

这实际上是将我们的代码向下移植到ES2015的过程。

因此,在代码编辑器内部,您认为自己正在执行所编写的代码,但是实际上,由于特别具有异步/等待语法,因此整个功能将扩展为babeljs.io右侧的内容。

因此,当我对您说动作创建者没有返回纯JavaScript对象时,是因为您具有异步/等待语法。这就是为什么您的动作创建者无法按预期工作的原因。

因此,您最初返回的不是您的操作对象,而是返回。因此,当您的动作创建者第一次被调用时,您不会返回该动作对象,而是如您所见,在其中包含了一些代码来返回您的请求对象。这就是返回请求的内容。因此,您从操作创建者返回了请求,该请求进入了store.dispatch方法。

然后,redux存储查看返回的内容并说好,这是仅具有type属性的普通JavaScript对象吗?好吧,在这种情况下,不,因为我们只是返回了请求对象,所以没有返回操作,这就是为什么我们最终看到讨厌的红色消息,说操作必须是普通对象。因此,我们没有返回普通对象,而操作必须返回普通对象。我们返回的请求对象可能已分配了一些精美的方法,而可能没有type属性,因此我们绝对没有分派我们认为分派的对象。

这是因为您使用的async / await语法。

这就是您的动作创建者的第一个问题。由于使用了异步/等待语法(可转换为es5代码),因此您在浏览器中实际运行的内容与您认为的实际运行情况不符。

因此,我们正在调度NOT Redux动作,正在调度Redux不关心的随机对象。

那么,我们如何正确利用称为Redux-Thunk的中间件呢?在回答这个问题之前,让我们了解一下Redux世界中的中间件。

中间件是普通的JavaScript函数,将在我们分派的每个动作中调用该中间件。在该功能内,中间件有机会阻止动作的分发,阻止其进入任何化简器,修改动作或以任何方式,形状或形式操纵动作。

Redux-Thunk是最受欢迎的中间件,因为它可以帮助我们与异步动作创建者一起工作。

好的,那么Redux-Thunk如何帮助我们解决此问题?

好吧,Redux-Thunk将放宽常规的动作创建者规则或Redux,就像我在上面所说的那样,Redux表示动作创建者必须返回动作对象,它必须具有type属性,并且必须具有payload属性。

Redux-Thunk没有内在的本质,它允许我们做很多事情,其中​​之一是处理动作创建者,但这不是其主要目的。

一旦我们的动作创建者参与了Redux-Thunk的创建,它就可以返回普通对象或返回函数。

你知道这是怎么回事吗?

那么返回函数有什么帮助呢?

因此,我们的动作创建者以对象或函数的形式返回“动作”。该“动作”将被发送到调度功能,最终将在Redux-Thunk内部结束。

Redux-Thunk会说:“嗨,行动,您是函数还是对象?” 如果“操作”告诉Redux-Thunk它的对象,则Redux-Thunk会说:“好,谢谢您停止操作,但是我更喜欢只处理函数”,然后Redux-Thunk会将“ action”推向减速器。

否则,Redux-Thunk会说:“哦,您是一个函数吗?不错!” 那么终极版-咚将调用你的函数,并将它传递的dispatchgetState函数作为参数。您已经获得了答案的语法版本,所以请允许我提供它的一个变体。

因此,不仅如此:

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

使用Redux-Thunk,您将包括以下内容:

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

现在,在上面的示例中,我正在使用动作创建者向外部API发出异步请求。因此,它dispatch具有无限的功能来更改应用程序Redux端的数据。

您看到我正在利用该数据,getState因此您还可以理解,除了dispatchgetState还将返回商店中的所有数据。这两个参数在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")
);
Run Code Online (Sandbox Code Playgroud)

请注意,我还导入了applyMiddleware。此功能是我们将中间件连接到Redux的方式。

因此,我将createStore前端应用到一个名为的变量中,store并在Provider存储中实现该变量,如下所示:

const store = createStore(reducers);

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

为了连接Redux-Thunk,作为第二个参数,我将这样调用applyMiddleware并传递thunk

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

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

然后在动作创建者内部进行一两个更改。我仍然可以返回带有类型属性的普通对象,这是一个选择,通过Redux-Thunk,我们仍然可以使普通的动作创建者返回对象,但是我们不必返回动作。

因此,与其返回动作,不如dispatch像这样调用和传入动作对象:

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

    dispatch({type: 'FETCH_POSTS', payload: response })
  }
};
Run Code Online (Sandbox Code Playgroud)

借助Redux-Thunk,我们可以使用async / await语法,因为该语法只会修改内部函数的返回值。该功能一无所获。Redux-Thunk不会获得返回内容的引用并利用它,我们可以返回还是不返回,我们从外部函数返回的内容就是我们所关心的。

重构上面刚刚分享的内容的一种常见方式如下:

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

    dispatch({type: 'FETCH_POSTS', payload: })
  }
};
Run Code Online (Sandbox Code Playgroud)

因此,如果您不使用getState该函数,则可以将其作为参数保留。您可以像这样使代码更简洁:

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

    dispatch({type: 'FETCH_POSTS', payload: response })
} 
Run Code Online (Sandbox Code Playgroud)

您将在许多Redux项目中看到这一点。而已。

  • 全面解释了 thunk 如何工作,但并没有真正回答 OP 的问题。另外,第二个代码块中的错误: `export const fetchPosts = async () =&gt; {return function(dispatch, getState) {...` 应该是 `export const fetchPosts = () =&gt;{return async function(dispatch, getState) ) {... ` 否则你只是发送一个 Promise 而不是一个 Action 或一个函数 /thunk (3认同)

mfr*_*fru 5

export const fetchUser = () => async (getState, dispatch) => {// your code here}
Run Code Online (Sandbox Code Playgroud)

需要是

export const fetchUser = () => async (dispatch, getState) => {// your code here}
Run Code Online (Sandbox Code Playgroud)

(getState,dispatch)!==(dispatchgetState

尽管我很高兴我最终解决了这个问题,但是那里的方式却令人沮丧。