Tools

Redux Reducer Generator

Build Redux reducers with consistent naming and clear actions. From basic CRUD to async patterns with Redux Toolkit.

โšกInstant๐Ÿ”’In your browserโœ“No signup
Live
    View as text

    Consistent naming in Redux

    Action types in Redux follow the pattern domain/ACTION_NAME or DOMAIN_ACTION_NAME. With Redux Toolkit, this simplifies: createSlice automatically generates action creators with names like sliceName/reducerName. Most common mistake: mixing conventions (camelCase vs UPPER_SNAKE_CASE) in the same project.

    Recommended structure: one slice per feature, not per data type. Example: cartSlice handles items, totals, discounts (all cart-related), not separate itemsSlice + totalsSlice. This reduces boilerplate and facilitates refactoring.

    For async actions with thunks, standard pattern is fetchUsers (thunk) which dispatches fetchUsersPending, fetchUsersFulfilled, fetchUsersRejected. Redux Toolkit generates them automatically with createAsyncThunk. Don't invent variants like fetchUsersStart or fetchUsersSuccess.

    Action patterns by use case

    Basic CRUD uses 5 minimum actions: fetch (load data), add/create (POST), update/edit (PUT/PATCH), delete/remove (DELETE), and set (replace complete state). UI state needs toggle, open, close, reset for modals, sidebars, dropdowns.

    Forms require setFieldValue (individual), setFieldError (validation), resetForm (clear), and submitForm (async). Wizard forms add nextStep, previousStep, goToStep. Auto-save uses saveDraft + debounce.

    Realtime with WebSocket: connectSocket (initiate), socketConnected (success), socketError (fail), socketReconnect (retry), disconnectSocket (cleanup). Presence actions: userJoined, userLeft, updatePresence (typing indicators, online status).

    Handle side effects and async logic

    Redux Toolkit recommends createAsyncThunk for any async logic. Typical example: fetchUsers makes GET, dispatches pending โ†’ fulfilled/rejected automatically. In slice, extraReducers listens to these actions. Avoid async logic directly in reducers (they're pure functions).

    Advanced patterns: optimistic updates (update UI before server confirm, rollback if fails), polling (refetch every N seconds with setInterval in thunk), retry logic (retry failed request with exponential backoff). Example: payment thunk retries 3 times before failing.

    Error handling: save error messages in state (error: string | null), not just booleans. Rejected actions should include action.error.message for debugging. For multiple simultaneous requests, use Promise.allSettled instead of Promise.all (doesn't break if one fails).

    Slice organization in large projects

    Recommended folder structure: /features/[feature]/[feature]Slice.ts + [feature]Thunks.ts + [feature]Selectors.ts. Example: /features/auth/authSlice.ts contains login, logout, session. Don't mix all slices in /store/index.ts.

    Use configureStore with implicit combineReducers. For normalized state (avoid nested objects), use createEntityAdapter: handles ids, entities, automatic CRUD. Example: usersAdapter.addOne, usersAdapter.updateMany are more efficient than manual spread.

    Selectors with createSelector (memoized) prevent unnecessary re-renders. Example: selectActiveUsers = createSelector([selectUsers], users => users.filter(u => u.active)). If users state didn't change, returns same array. Testing: mock store with configureStore({ reducer, preloadedState }), don't use real store in tests.

    FAQ

    When to use Redux vs Context API?

    Redux for complex state shared across multiple features (auth, user, cart). Context for simple localized state (theme, language). Redux offers devtools, middleware, time-travel debugging.

    Should I create an action per form field?

    No. Use a generic setFieldValue(field, value) action that updates any field. This reduces massive boilerplate in large forms.

    How to handle loading states of multiple requests?

    Use an object loading: { users: 'idle' | 'pending' | 'succeeded' | 'failed' } instead of a global boolean. Allows granular tracking per entity.

    Can I dispatch actions from a reducer?

    No, reducers are pure functions. For side effects (dispatch another action), use middleware (thunks, sagas) or listeners (RTK Listener API).

    Was this generator useful?