Skip to content

Redux getState() Returning Undefined with configureStore()

Problem: getState() Returns Undefined in Redux Actions

When migrating from createStore() to Redux Toolkit's configureStore(), developers often encounter issues where getState() returns undefined in their actions. This typically occurs when the Redux store setup doesn't properly integrate with the middleware system that provides access to the getState function.

The core issue appears in actions that require authentication, where attempting to access user information from the state fails:

javascript
export const addProduct = product => async (dispatch, getState) => {
  try {
    // ...
    const { userLogin: { userInfo } } = getState() // Returns undefined
    // ...
  } catch (error) {
    // Error handling
  }
}

Root Cause: configureStore vs createStore Differences

Redux Toolkit's configureStore() automatically sets up middleware and store configuration, but your setup may have compatibility issues with legacy Redux patterns.

Solutions

1. Verify Redux Thunk Middleware Configuration

Ensure proper middleware configuration when using configureStore():

javascript
import { configureStore } from '@reduxjs/toolkit'
import thunk from 'redux-thunk'

const store = configureStore({
  reducer: rootReducer,
  preloadedState: initialState,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(thunk),
})

export default store

2. Migrate to Modern Redux Patterns

The Redux team recommends using Redux Toolkit for all new projects and migrating existing codebases to modern patterns:

javascript
// Instead of hand-written actions and reducers:
import { createSlice, configureStore } from '@reduxjs/toolkit'

const userSlice = createSlice({
  name: 'user',
  initialState: { userInfo: null },
  reducers: {
    loginSuccess: (state, action) => {
      state.userInfo = action.payload
    },
    logout: (state) => {
      state.userInfo = null
    }
  }
})

export const { loginSuccess, logout } = userSlice.actions

const store = configureStore({
  reducer: {
    user: userSlice.reducer,
    // other reducers
  }
})

3. Create Async Thunks with createAsyncThunk

Use Redux Toolkit's createAsyncThunk for API calls with automatic access to state:

javascript
import { createAsyncThunk } from '@reduxjs/toolkit'

export const addProduct = createAsyncThunk(
  'products/add',
  async (product, { getState }) => {
    const { user } = getState()
    const config = {
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${user.userInfo.token}`,
      },
    }
    
    const response = await axios.post('/product', product, config)
    return response.data
  }
)

4. Legacy Approach (Temporary Fix)

If you need a quick fix without immediate migration:

javascript
import { legacy_createStore as createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'

const store = createStore(
  rootReducer,
  initialState,
  applyMiddleware(thunk)
)

WARNING

This is a temporary solution. The Redux team has deprecated createStore to encourage migration to modern patterns with Redux Toolkit.

Best Practices for State Access

  1. Use Selectors: Create reusable selector functions to access state:
javascript
// Selectors
export const selectUserInfo = (state) => state.user.userInfo

// In your component or thunk
import { selectUserInfo } from './selectors'
const userInfo = selectUserInfo(getState())
  1. Middleware Configuration: Always use the functional form of middleware configuration with configureStore to ensure compatibility:
javascript
const store = configureStore({
  reducer,
  preloadedState,
  middleware: (getDefaultMiddleware) => 
    getDefaultMiddleware({
      thunk: {
        extraArgument: { /* additional arguments */ }
      }
    })
})
  1. Check State Before Access: Add safety checks for state access:
javascript
export const addProduct = product => async (dispatch, getState) => {
  const state = getState()
  const userInfo = state.userLogin?.userInfo
  
  if (!userInfo?.token) {
    // Handle unauthorized access
    return
  }
  
  // Continue with API call
}

Migration Path

Follow the official Redux migration guide:

  1. Install Redux Toolkit: npm install @reduxjs/toolkit
  2. Replace createStore with configureStore
  3. Convert hand-written reducers to createSlice
  4. Replace thunk actions with createAsyncThunk
  5. Update components to use the React-Redux hooks API

INFO

The deprecation of createStore is primarily an educational effort by the Redux team to guide developers toward modern, less error-prone patterns. Your existing code will continue to work, but migrating to Redux Toolkit will result in less boilerplate and fewer bugs.

Additional Resources

By adopting Redux Toolkit's recommended patterns, you'll avoid the getState() undefined issue while writing more maintainable and efficient Redux code.