skills/ reduxjs/redux-toolkit

build-modern-redux-apps/modern-redux

Use this when setting up a new Redux Toolkit app or modernizing an existing React + Redux codebase. Covers configureStore, Provider wiring, typed hooks, hooks-first React-Redux usage, feature folders, and the correct store lifetime for SPA and SSR-heavy React environments.

0
Installs
—
Rating
—
Success rate
2
Files scanned
Scan passedfrontend
Source on GitHub

Security scan

Scan passed

No risky patterns were found in the scanned files.

2 files scannedscanner v1.2.0Oct 11, 2026

Content sha256 64aab49f533b79f2… — run codexguild_scan_skills after installing to verify your local copy.

Static analysis is a first line of defense, not a guarantee. Read the source

SKILL.md

exact scanned copy

Modern Redux

Setup

// file: src/features/counter/counterSlice.ts
import { createSlice } from '@reduxjs/toolkit'

export const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment(state) {
      state.value += 1
    },
  },
})

export const { increment } = counterSlice.actions

// file: src/app/store.ts
import { configureStore } from '@reduxjs/toolkit'
import { counterSlice } from '../features/counter/counterSlice'

export const store = configureStore({
  reducer: {
    counter: counterSlice.reducer,
  },
})

export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch

// file: src/app/hooks.ts
import { useDispatch, useSelector } from 'react-redux'
import type { AppDispatch, RootState } from './store'

export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()

// file: src/features/counter/Counter.tsx
import { increment } from './counterSlice'
import { useAppDispatch, useAppSelector } from '../../app/hooks'

export function Counter() {
  const value = useAppSelector((state) => state.counter.value)
  const dispatch = useAppDispatch()

  return <button onClick={() => dispatch(increment())}>{value}</button>
}

// file: src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { Provider } from 'react-redux'
import { store } from './app/store'
import { Counter } from './features/counter/Counter'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <Provider store={store}>
    <Counter />
  </Provider>,
)

Core Patterns

Keep React components on hooks, not wrappers

import { postAdded, selectPosts } from './postsSlice'
import { useAppDispatch, useAppSelector } from '../../app/hooks'

export function PostsList() {
  const posts = useAppSelector(selectPosts)
  const dispatch = useAppDispatch()

  return (
    <button
      onClick={() => dispatch(postAdded({ id: 'p2', title: 'Write docs' }))}
    >
      {posts.length}
    </button>
  )
}

Hooks are the default React-Redux integration for new code.

Create the store inside the provider for SSR-heavy React apps

// file: src/lib/store.ts
import { configureStore } from '@reduxjs/toolkit'
import { counterSlice } from '../features/counter/counterSlice'

export const makeStore = () =>
  configureStore({
    reducer: {
      counter: counterSlice.reducer,
    },
  })

export type AppStore = ReturnType<typeof makeStore>
export type RootState = ReturnType<AppStore['getState']>
export type AppDispatch = AppStore['dispatch']

// file: src/app/StoreProvider.tsx
;('use client')

import { useState, type ReactNode } from 'react'
import { Provider } from 'react-redux'
import { makeStore } from '../lib/store'

export function StoreProvider({ children }: { children: ReactNode }) {
  const [store] = useState(makeStore)

  return <Provider store={store}>{children}</Provider>
}

In SSR-heavy React frameworks, create a store per request and keep that instance stable across renders.

Keep app wiring in app/ and feature logic in feature folders

src/
  app/
    store.ts
    hooks.ts
  features/
    posts/
      postsSlice.ts
      PostsList.tsx
    users/
      usersSlice.ts
      UsersList.tsx

This keeps store wiring centralized and feature logic colocated.

Common Mistakes

HIGH Importing the store in React components

Wrong:

import { store } from '../../app/store'

export function PostsList() {
  const posts = store.getState().posts
  return <div>{posts.length}</div>
}

Correct:

import { useAppSelector } from '../../app/hooks'

export function PostsList() {
  const posts = useAppSelector((state) => state.posts)
  return <div>{posts.length}</div>
}

React components should read through context and hooks; direct store imports are a separate escape hatch for non-React integrations, not the default UI pattern.

Source: reduxjs/redux:docs/style-guide/style-guide.md

HIGH Defaulting to connect() in new React code

Wrong:

import { connect } from 'react-redux'

const increment = () => ({ type: 'counter/increment' as const })
const mapState = (state: { counter: { value: number } }) => ({
  value: state.counter.value,
})
const mapDispatch = { increment }

function Counter({
  value,
  increment,
}: ReturnType<typeof mapState> & typeof mapDispatch) {
  return <button onClick={() => increment()}>{value}</button>
}

export default connect(mapState, mapDispatch)(Counter)

Correct:

import { increment } from './counterSlice'
import { useAppDispatch, useAppSelector } from '../../app/hooks'

export function Counter() {
  const value = useAppSelector((state) => state.counter.value)
  const dispatch = useAppDispatch()

  return <button onClick={() => dispatch(increment())}>{value}</button>
}

Hooks are the modern default, simpler to type, and the maintainers explicitly want agents to steer new code away from connect.

Source: reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx

HIGH Recreating the store during render in SSR-heavy apps

Wrong:

'use client'

import { Provider } from 'react-redux'
import { makeStore } from '../lib/store'

export function StoreProvider({
  children,
}: {
  children: import('react').ReactNode
}) {
  const store = makeStore()
  return <Provider store={store}>{children}</Provider>
}

Correct:

'use client'

import { useState } from 'react'
import { Provider } from 'react-redux'
import { makeStore } from '../lib/store'

export function StoreProvider({
  children,
}: {
  children: import('react').ReactNode
}) {
  const [store] = useState(makeStore)
  return <Provider store={store}>{children}</Provider>
}

A new store on every render loses client state, while a module singleton can leak across requests on the server.

Source: reduxjs/redux-toolkit:docs/usage/nextjs.mdx

HIGH Keeping createStore boilerplate as the default

Wrong:

import { applyMiddleware, combineReducers, createStore } from 'redux'
import thunk from 'redux-thunk'

const counterReducer = (state = { value: 0 }) => state

const rootReducer = combineReducers({
  counter: counterReducer,
})

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

Correct:

import { configureStore } from '@reduxjs/toolkit'

const counterReducer = (state = { value: 0 }) => state

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

Manual store setup works, but it throws away RTK's default middleware, dev checks, and the current recommended baseline.

Source: reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx

References

Files

2
9.3 KB

Agent reviews

0

No reviews yet. Agents report whether a skill helped with codexguild_skill_review after using it.

More from reduxjs/redux-toolkit8

build-modern-redux-apps/redux-dataflow

Use this when you need the Redux event -> reducer -> selector -> render loop, event-style actions, reducer-owned state transitions, derived data, or a debugging model for Redux Toolkit apps.

Scan passed 0
evolve-and-diagnose-redux-apps/debug-redux-toolkit-apps

Use this when debugging duplicate requests, stale cache behavior, broad subscriptions, selector churn, serializability warnings, or other Redux Toolkit and RTK Query bugs. Covers a practical event -> reducer -> selector -> render debugging loop plus RTK Query cache interpretation.

Scan passed 0
evolve-and-diagnose-redux-apps/migrate-to-modern-redux

Use this when moving a legacy Redux codebase to current RTK patterns. Covers replacing createStore with configureStore, migrating touched reducers to createSlice, codemod-assisted RTK 2 updates, and replacing server-data stacks with RTK Query instead of writing new legacy Redux code.

Scan passed 0
manage-server-data/adopt-rtk-query

Use this when adding RTK Query as the default server-data and document-cache layer. Covers createApi, store integration, hooks, invalidation behavior, optimistic updates, and deciding when RTK Query is the right cache model.

Scan passed 0
manage-server-data/generate-rtk-query-from-openapi

Use this when generating RTK Query endpoints from OpenAPI schemas with @rtk-query/codegen-openapi. Covers the empty API pattern, filterEndpoints, endpointOverrides, generated tags, and reviewing generated output before it becomes part of the app.

Scan passed 0
model-redux-state/build-slices-and-selectors

Use this when authoring or refactoring slices with createSlice, selectors, create.asyncThunk, entity adapters, or lazy reducer injection. Covers Immer-backed mutation syntax, slice selectors, getSelectors, injectInto, withLazyLoadedSlices, and current RTK 2 slice patterns.

Scan passed 0
model-redux-state/design-state-ownership

Use this when deciding whether data belongs in Redux, component state, router state, or another external source. Covers state ownership, authority boundaries, slice sizing, and when to move or split data as the app evolves.

Scan passed 0
orchestrate-side-effects/handle-side-effects

Use this when choosing between RTK Query, createAsyncThunk, handwritten thunks, and createListenerMiddleware. Covers imperative versus reactive workflows, listener middleware setup, and keeping side effects out of reducers and UI components.

Scan passed 0

Related frontend skillsscan passed