Search code examples
typescriptreduxreact-reduxredux-thunkredux-toolkit

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


I keep getting dispatch error with redux/ typescript. Would be great if someone can help correct the setup I have here:

Store:

import {
  configureStore,
  combineReducers,
  MiddlewareArray,
} from '@reduxjs/toolkit'

import { useDispatch } from 'react-redux'

//import slice as reducer
import userReducer from './features/userSlice'
import heroReducer from './features/heroSlice'
import menuReducer from './features/menuSlice'
import utilsReducer from './features/utilsSlice'
import templatesReducer from './features/templatesSlice'

const rootReducer = combineReducers({
  //combine all reducers
  user: userReducer,
  hero: heroReducer,
  menu: menuReducer,
  utils: utilsReducer,
  templates: templatesReducer,
})


export const store = configureStore({
  reducer: rootReducer,
  middleware: new MiddlewareArray(),
})

export type AppDispatch = typeof store.dispatch
export const useAppDispatch = () => useDispatch<AppDispatch>()

where the dispatch is happening:

  useEffect(() => {
    const fetchData = () => {
      // TODO
      dispatch(fetchUser()).  <--- error portion
    }
    fetchData()
  }, [])

user slice:

import { createSlice, createSelector, createAsyncThunk } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'

import axios from 'axios'

export const fetchUser = createAsyncThunk(
  'user/fetchUser',
  async (thunkAPI) => {
    try {
      const response = await axios.get('/api/user', {
        headers: {
          'Content-Type': 'application/json',
        },
      })
      return response.data
    } catch (error) {
      // return rejectWithValue({ error: error.message })
      return console.log(error.message)
    }
  }
)

const userSlice = createSlice({
  name: 'user',
  initialState: {
    userData: {},
    isSubscribed: false,
  },
  reducers: {
    setUserData: (state: any, action: any) => {
      state.userData = action.payload.userData
    },
    setIsSubscribed: (state: any, action: any) => {
      state.isSubscribed = action.payload.isSubscribed
    },
  },
  extraReducers: (builder) => {
    builder.addCase(fetchUser.fulfilled, (state: any, action: any) => {
      state.userData = action.payload
      state.isSubscribed = action.payload.isSubscribed
    })
  },
})

export const userData = createSelector(
  (state: any) => ({
    userData: state.userData,
    isSubscribed: state.isSubscribed,
  }),
  (state: any) => state.userData
)

export const { setUserData, setIsSubscribed } = userSlice.actions
export default userSlice.reducer

Not too sure what else is needed to get rid of type errors?

Original error:

Error: Actions must be plain objects. Use custom middleware for async actions.

Type Error on dispatch(fetchUser())

'Argument of type 'AsyncThunkAction<any, void, {}>' is not assignable to parameter of type 'AnyAction''

npm ls redux shows:

enter image description here


Solution

  • Your middleware: new MiddlewareArray() removes all middleware from the store - while usually a few would be included. Among them is redux-thunk, which allows for the dispatch of thunks.

    Change it to:

    export const store = configureStore({
      reducer: rootReducer,
    })
    

    By the way you also don't need combineReducers, so you can do

    export const store = configureStore({
      reducer: {
        user: userReducer,
        hero: heroReducer,
        menu: menuReducer,
        utils: utilsReducer,
        templates: templatesReducer,
      },
    })