You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux异步请求自定义中间件创建及dispatch报错排查

Great questions! Let's tackle them one by one, starting with the error you're facing since that's the immediate roadblock.

1. Why You're Seeing "Actions must be plain objects" Error

First, let's break down what's happening here:

  • Redux's default behavior only accepts plain JavaScript objects as actions. These objects must have a type property (and usually a payload).
  • Your getPostById is an async function—any async function automatically returns a Promise when called, not a plain object. When you pass that Promise to dispatch, Redux doesn't know how to handle it, hence the error.

On top of that, your current getPostById doesn't even return an action object at all! It fetches data but doesn't do anything with it. Let's fix that first, then talk about middleware.

Fixing the Action (with Thunk Pattern)

If you use a middleware like Redux Thunk (the most common solution for async actions), your action can return a function instead of a plain object. That function will receive dispatch as an argument, letting you dispatch the actual plain-object action once the async work is done. Here's the corrected getPostById:

export const getPostById = (id) => async (dispatch) => {
  const myResponse = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  const myJson = await myResponse.json();
  // Now dispatch a plain object action with the fetched data
  dispatch({ type: GET_ID, payload: myJson.body });
};

Updating mapDispatchToProps

With this corrected action, your original mapDispatchToProps will work—but only if you have Redux Thunk middleware set up in your store. You can even simplify mapDispatchToProps using the shorthand syntax for connect:

// Shorthand version (avoids writing the function manually)
const mapDispatchToProps = {
  getPostByIdAction: getPostById
};

2. Creating a Custom Async Middleware for Redux

If you don't want to use Redux Thunk and want to build your own middleware, here's how it works. Redux middleware follows a curried structure: (store) => (next) => (action) => {}—it gets access to the store, the next middleware in the chain, and the current action.

Let's build a middleware that handles two common async patterns: functions (like thunks) and Promises.

Step 1: Write the Middleware

const customAsyncMiddleware = (store) => (next) => (action) => {
  // Handle thunk-style actions (functions that receive dispatch/getState)
  if (typeof action === 'function') {
    return action(store.dispatch, store.getState);
  }

  // Handle Promise-based actions (wait for resolution, then dispatch the result)
  if (action instanceof Promise) {
    return action
      .then((resolvedAction) => store.dispatch(resolvedAction))
      .catch((error) => {
        // Optional: Dispatch an error action to handle failures
        store.dispatch({ type: 'ASYNC_REQUEST_FAILED', payload: error });
        throw error; // Re-throw so the caller can handle it too
      });
  }

  // For plain object actions: pass them to the next middleware/reducer
  return next(action);
};

Step 2: Add It to Your Redux Store

You need to apply the middleware when creating your store using applyMiddleware:

import { createStore, applyMiddleware } from 'redux';
import { rootReducer } from './reducers';
import { customAsyncMiddleware } from './middleware';

const store = createStore(
  rootReducer,
  applyMiddleware(customAsyncMiddleware)
);

Using the Custom Middleware

Now you can use either thunk-style functions (like the corrected getPostById above) or Promise-based actions. For example, a Promise-based version of getPostById would look like this:

export const getPostById = (id) => {
  return fetch(`https://jsonplaceholder.typicode.com/posts/${id}`)
    .then(res => res.json())
    .then(data => ({ type: GET_ID, payload: data.body }));
};

Your custom middleware will wait for the Promise to resolve, then dispatch the plain-object action it returns.


内容的提问来源于stack exchange,提问作者Alina Homyakova

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 14:52:33