reduxjs / redux-toolkit

The official, opinionated, batteries-included toolset for efficient Redux development
https://redux-toolkit.js.org
MIT License
10.62k stars 1.15k forks source link

Actions must be plain objects. Use custom middleware for async actions. #4499

Closed shojib116 closed 1 month ago

shojib116 commented 1 month ago

I am using @reduxjs/toolkit v2.2.6, redux v5.0.1 and react-redux v9.1.2

I've written the following code

// src/reducers/notificationReducer.js

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  message: null,
  status: null,
};

const notificationSlice = createSlice({
  name: "notification",
  initialState,
  reducers: {
    newNotification(state, action) {
      return action.payload;
    },
    clearNotification(state, action) {
      return null;
    },
  },
});

export const { newNotification, clearNotification } = notificationSlice.actions;

export const setNotification = (message, time) => {
  clearTimeout(setNotification.timout);
  return async (dispatch) => {
    dispatch(newNotification(message));
    setNotification.timout = setTimeout(() => {
      dispatch(clearNotification());
    }, time * 1000);
  };
};

setNotification.timout = null;

export default notificationSlice.reducer;
// src/store.js

import { configureStore } from "@reduxjs/toolkit";
import notificationReducer from "./reducers/notificationReducer";

const store = configureStore({
  reducer: {
    notification: notificationReducer,
  },
});

export default store;
// src/main.jsx

import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";

ReactDOM.createRoot(document.getElementById("root")).render(
  <Provider store={store}>
    <App />
  </Provider>
);
// src/App.jsx

// ...
import { useDispatch } from "react-redux";

//...
const App = () => {
  const dispatch = useDispatch();
  //...
  const handleLogin = async (userObject) => {
    try {
      //...
    } catch (error) {
      dispatch(setNotification(error.response.data.error, "error"));
    }
  };
  //...
}

when there's an error, I am getting the following error Error: Actions must be plain objects. Use custom middleware for async actions.

I've used exactly the same code two days ago. it was working seamlessly there. (redux v4.2.1, @reduxjs/toolkit v2.2.6, react-redux v8.1.3) But, in this new project I am getting this error. I tried going back to the exact package version of the previous project. But still did not work. According to redux thunk documentation, If configureStore is used, the thunk middleware is already applied. then, why is this error appearing inconsistently?

shojib116 commented 1 month ago

This is now working when I added another reducer to the store. don't know why it is behaving like this!

markerikson commented 1 month ago

Yeah, honestly no idea why. Also surprised to see that particular error message - Redux 4.2 changed that error message to:

      throw new Error(
        `Actions must be plain objects. Instead, the actual type was: '${kindOf(
          action
        )}'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions. See https://redux.js.org/tutorials/fundamentals/part-4-store#middleware and https://redux.js.org/tutorials/fundamentals/part-6-async-logic#using-the-redux-thunk-middleware for examples.`
      )
shojib116 commented 1 month ago

Yeah, honestly no idea why. Also surprised to see that particular error message - Redux 4.2 changed that error message to:

      throw new Error(
        `Actions must be plain objects. Instead, the actual type was: '${kindOf(
          action
        )}'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions. See https://redux.js.org/tutorials/fundamentals/part-4-store#middleware and https://redux.js.org/tutorials/fundamentals/part-6-async-logic#using-the-redux-thunk-middleware for examples.`
      )

Could you please shed some light on this peculiar behaviour? why the error persists when there is only one reducer and vanishes when there are more than one?

markerikson commented 1 month ago

Absolutely no idea, sorry :(