@depup/reduxjs__toolkit 2.12.0-depup.28 → 2.13.0-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +4 -4
  2. package/changes.json +3 -3
  3. package/dist/cjs/redux-toolkit.development.cjs +1755 -2247
  4. package/dist/cjs/redux-toolkit.development.cjs.map +1 -1
  5. package/dist/cjs/redux-toolkit.production.min.cjs +1 -2
  6. package/dist/cjs/redux-toolkit.production.min.cjs.map +1 -1
  7. package/dist/index.d.mts +1496 -1525
  8. package/dist/index.d.ts +1496 -1525
  9. package/dist/query/cjs/rtk-query.development.cjs +2059 -2990
  10. package/dist/query/cjs/rtk-query.development.cjs.map +1 -1
  11. package/dist/query/cjs/rtk-query.production.min.cjs +1 -1
  12. package/dist/query/cjs/rtk-query.production.min.cjs.map +1 -1
  13. package/dist/query/index.d.mts +2300 -2308
  14. package/dist/query/index.d.ts +2300 -2308
  15. package/dist/query/react/cjs/rtk-query-react.development.cjs +609 -714
  16. package/dist/query/react/cjs/rtk-query-react.development.cjs.map +1 -1
  17. package/dist/query/react/cjs/rtk-query-react.production.min.cjs +1 -1
  18. package/dist/query/react/cjs/rtk-query-react.production.min.cjs.map +1 -1
  19. package/dist/query/react/index.d.mts +516 -523
  20. package/dist/query/react/index.d.ts +516 -523
  21. package/dist/query/react/rtk-query-react.browser.mjs +1 -1
  22. package/dist/query/react/rtk-query-react.browser.mjs.map +1 -1
  23. package/dist/query/react/rtk-query-react.legacy-esm.js +672 -714
  24. package/dist/query/react/rtk-query-react.legacy-esm.js.map +1 -1
  25. package/dist/query/react/rtk-query-react.modern.mjs +586 -679
  26. package/dist/query/react/rtk-query-react.modern.mjs.map +1 -1
  27. package/dist/query/rtk-query.browser.mjs +1 -1
  28. package/dist/query/rtk-query.browser.mjs.map +1 -1
  29. package/dist/query/rtk-query.legacy-esm.js +2175 -3014
  30. package/dist/query/rtk-query.legacy-esm.js.map +1 -1
  31. package/dist/query/rtk-query.modern.mjs +2052 -2949
  32. package/dist/query/rtk-query.modern.mjs.map +1 -1
  33. package/dist/react/cjs/redux-toolkit-react.development.cjs +30 -51
  34. package/dist/react/cjs/redux-toolkit-react.development.cjs.map +1 -1
  35. package/dist/react/cjs/redux-toolkit-react.production.min.cjs +1 -1
  36. package/dist/react/cjs/redux-toolkit-react.production.min.cjs.map +1 -1
  37. package/dist/react/index.d.mts +12 -15
  38. package/dist/react/index.d.ts +12 -15
  39. package/dist/react/redux-toolkit-react.browser.mjs +1 -1
  40. package/dist/react/redux-toolkit-react.browser.mjs.map +1 -1
  41. package/dist/react/redux-toolkit-react.legacy-esm.js +83 -44
  42. package/dist/react/redux-toolkit-react.legacy-esm.js.map +1 -1
  43. package/dist/react/redux-toolkit-react.modern.mjs +23 -25
  44. package/dist/react/redux-toolkit-react.modern.mjs.map +1 -1
  45. package/dist/redux-toolkit.browser.mjs +1 -2
  46. package/dist/redux-toolkit.browser.mjs.map +1 -1
  47. package/dist/redux-toolkit.legacy-esm.js +1748 -2201
  48. package/dist/redux-toolkit.legacy-esm.js.map +1 -1
  49. package/dist/redux-toolkit.modern.mjs +1670 -2171
  50. package/dist/redux-toolkit.modern.mjs.map +1 -1
  51. package/package.json +17 -33
  52. package/skills/build-modern-redux-apps/modern-redux/SKILL.md +23 -14
  53. package/skills/build-modern-redux-apps/modern-redux/references/store-lifetime.md +6 -6
  54. package/skills/build-modern-redux-apps/redux-dataflow/SKILL.md +13 -10
  55. package/skills/evolve-and-diagnose-redux-apps/debug-redux-toolkit-apps/SKILL.md +6 -6
  56. package/skills/evolve-and-diagnose-redux-apps/migrate-to-modern-redux/SKILL.md +7 -8
  57. package/skills/manage-server-data/adopt-rtk-query/SKILL.md +13 -11
  58. package/skills/model-redux-state/build-slices-and-selectors/SKILL.md +26 -14
  59. package/skills/model-redux-state/design-state-ownership/SKILL.md +11 -12
  60. package/skills/model-redux-state/design-state-ownership/references/state-ownership.md +6 -6
  61. package/skills/orchestrate-side-effects/handle-side-effects/SKILL.md +27 -23
  62. package/skills/orchestrate-side-effects/handle-side-effects/references/listener-workflows.md +4 -4
  63. package/src/autoBatchEnhancer.ts +5 -3
  64. package/src/combineSlices.ts +5 -5
  65. package/src/createAction.ts +11 -6
  66. package/src/createAsyncThunk.ts +14 -2
  67. package/src/createReducer.ts +1 -1
  68. package/src/createSlice.ts +9 -4
  69. package/src/dynamicMiddleware/index.ts +21 -5
  70. package/src/entities/models.ts +2 -1
  71. package/src/entities/sorted_state_adapter.ts +35 -24
  72. package/src/entities/unsorted_state_adapter.ts +1 -1
  73. package/src/immutableStateInvariantMiddleware.ts +34 -5
  74. package/src/listenerMiddleware/types.ts +10 -10
  75. package/src/mapBuilders.ts +2 -5
  76. package/src/matchers.ts +7 -1
  77. package/src/query/core/apiState.ts +1 -1
  78. package/src/query/core/buildInitiate.ts +19 -15
  79. package/src/query/core/buildMiddleware/cacheLifecycle.ts +3 -1
  80. package/src/query/core/buildMiddleware/index.ts +1 -1
  81. package/src/query/core/buildMiddleware/invalidationByTags.ts +4 -1
  82. package/src/query/core/buildMiddleware/polling.ts +12 -3
  83. package/src/query/core/buildMiddleware/types.ts +5 -2
  84. package/src/query/core/buildSlice.ts +2 -2
  85. package/src/query/core/buildThunks.ts +19 -0
  86. package/src/query/core/module.ts +9 -3
  87. package/src/query/createApi.ts +4 -1
  88. package/src/query/endpointDefinitions.ts +15 -9
  89. package/src/query/fetchBaseQuery.ts +1 -1
  90. package/src/query/react/buildHooks.ts +54 -51
  91. package/src/query/react/namedHooks.ts +28 -24
  92. package/src/query/utils/isAbsoluteUrl.ts +8 -3
  93. package/src/serializableStateInvariantMiddleware.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@depup/reduxjs__toolkit",
3
- "version": "2.12.0-depup.28",
3
+ "version": "2.13.0-depup.0",
4
4
  "description": "The official, opinionated, batteries-included toolset for efficient Redux development (with updated dependencies)",
5
5
  "author": "Mark Erikson <mark@isquaredsoftware.com>",
6
6
  "license": "MIT",
@@ -187,7 +187,7 @@
187
187
  }
188
188
  },
189
189
  "devDependencies": {
190
- "@arethetypeswrong/cli": "^0.18.2",
190
+ "@arethetypeswrong/cli": "^0.18.3",
191
191
  "@babel/core": "^7.24.8",
192
192
  "@babel/helper-module-imports": "^7.24.7",
193
193
  "@microsoft/api-extractor": "^7.13.2",
@@ -205,48 +205,32 @@
205
205
  "@types/query-string": "^6.3.0",
206
206
  "@types/react": "^19.0.1",
207
207
  "@types/react-dom": "^19.0.1",
208
- "@typescript-eslint/eslint-plugin": "^6",
209
- "@typescript-eslint/parser": "^6",
210
208
  "axios": "^0.19.2",
211
- "esbuild": "^0.25.1",
212
- "esbuild-extra": "^0.4.0",
213
- "eslint": "^7.25.0",
214
- "eslint-config-prettier": "^9.1.0",
215
- "eslint-config-react-app": "^7.0.1",
216
- "eslint-plugin-flowtype": "^5.7.2",
217
- "eslint-plugin-import": "^2.22.1",
218
- "eslint-plugin-jsx-a11y": "^6.4.1",
219
- "eslint-plugin-prettier": "^5.1.3",
220
- "eslint-plugin-react": "^7.23.2",
221
- "eslint-plugin-react-hooks": "^4.2.0",
222
209
  "jsdom": "^25.0.1",
223
- "msw": "^2.1.4",
210
+ "msw": "2.1.5",
224
211
  "node-fetch": "^3.3.2",
225
- "prettier": "^3.2.5",
226
212
  "query-string": "^7.0.1",
227
213
  "react": "^19.0.0",
228
214
  "react-dom": "^19.0.0",
229
215
  "react-redux": "^9.2.0",
230
216
  "rimraf": "^6.1.3",
231
217
  "size-limit": "^11.0.1",
232
- "tsup": "^8.4.0",
218
+ "tsdown": "^0.22.14",
233
219
  "tsx": "^4.19.0",
234
- "typescript": "^5.9.3",
220
+ "typescript": "^6.0.3",
221
+ "unrun": "^0.3.1",
235
222
  "valibot": "^1.0.0",
236
223
  "vite-tsconfig-paths": "^4.3.1",
237
- "vitest": "^4"
224
+ "vitest": "^5"
238
225
  },
239
226
  "scripts": {
240
227
  "clean": "rimraf dist",
241
- "run-build": "tsup --config=$INIT_CWD/tsup.config.mts",
242
- "build": "yarn clean && yarn run-build && tsx scripts/fixUniqueSymbolExports.mts",
243
- "build-only": "yarn clean && yarn run-build",
244
- "format": "prettier --write \"(src|examples)/**/*.{ts,tsx}\" \"**/*.md\"",
245
- "format:check": "prettier --list-different \"(src|examples)/**/*.{ts,tsx}\" \"docs/*/**.md\"",
246
- "lint": "eslint src examples",
228
+ "run-build": "tsdown --config=./tsdown.config.mts --config-loader unrun",
229
+ "build": "pnpm clean && pnpm run-build && tsx scripts/fixUniqueSymbolExports.mts && tsx scripts/stripSourcemapFileField.mts",
230
+ "build-only": "pnpm clean && pnpm run-build",
247
231
  "test": "vitest --typecheck --run ",
248
232
  "test:watch": "vitest --watch",
249
- "type-tests": "yarn tsc -p tsconfig.test.json --noEmit",
233
+ "type-tests": "pnpm exec tsc -p tsconfig.test.json --noEmit",
250
234
  "size": "size-limit"
251
235
  },
252
236
  "files": [
@@ -264,10 +248,10 @@
264
248
  "dependencies": {
265
249
  "@standard-schema/spec": "^1.1.0",
266
250
  "@standard-schema/utils": "^0.3.0",
267
- "immer": "^11.1.15",
251
+ "immer": "^11.1.18",
268
252
  "redux": "^5.0.1",
269
253
  "redux-thunk": "^3.1.0",
270
- "reselect": "^5.2.0"
254
+ "reselect": "^5.3.0"
271
255
  },
272
256
  "peerDependencies": {
273
257
  "react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
@@ -294,17 +278,17 @@
294
278
  },
295
279
  "immer": {
296
280
  "from": "^11.0.0",
297
- "to": "^11.1.15"
281
+ "to": "^11.1.18"
298
282
  },
299
283
  "reselect": {
300
284
  "from": "^5.1.0",
301
- "to": "^5.2.0"
285
+ "to": "^5.3.0"
302
286
  }
303
287
  },
304
288
  "depsUpdated": 3,
305
289
  "originalPackage": "@reduxjs/toolkit",
306
- "originalVersion": "2.12.0",
307
- "processedAt": "2026-07-21T17:20:38.831Z",
290
+ "originalVersion": "2.13.0",
291
+ "processedAt": "2026-09-29T08:13:47.731Z",
308
292
  "smokeTest": "passed"
309
293
  }
310
294
  }
@@ -6,16 +6,16 @@ description: >
6
6
  hooks-first React-Redux usage, feature folders, and the correct store lifetime
7
7
  for SPA and SSR-heavy React environments.
8
8
  type: lifecycle
9
- library: "@reduxjs/toolkit"
10
- library_version: "2.11.2"
9
+ library: '@reduxjs/toolkit'
10
+ library_version: '2.11.2'
11
11
  requires:
12
12
  - build-modern-redux-apps/redux-dataflow
13
13
  sources:
14
- - "reduxjs/redux-toolkit:docs/tutorials/quick-start.mdx"
15
- - "reduxjs/redux-toolkit:docs/tutorials/typescript.md"
16
- - "reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx"
17
- - "reduxjs/redux-toolkit:docs/usage/nextjs.mdx"
18
- - "reduxjs/redux:docs/style-guide/style-guide.md"
14
+ - 'reduxjs/redux-toolkit:docs/tutorials/quick-start.mdx'
15
+ - 'reduxjs/redux-toolkit:docs/tutorials/typescript.md'
16
+ - 'reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx'
17
+ - 'reduxjs/redux-toolkit:docs/usage/nextjs.mdx'
18
+ - 'reduxjs/redux:docs/style-guide/style-guide.md'
19
19
  ---
20
20
 
21
21
  # Modern Redux
@@ -97,9 +97,7 @@ export function PostsList() {
97
97
 
98
98
  return (
99
99
  <button
100
- onClick={() =>
101
- dispatch(postAdded({ id: 'p2', title: 'Write docs' }))
102
- }
100
+ onClick={() => dispatch(postAdded({ id: 'p2', title: 'Write docs' }))}
103
101
  >
104
102
  {posts.length}
105
103
  </button>
@@ -128,7 +126,7 @@ export type RootState = ReturnType<AppStore['getState']>
128
126
  export type AppDispatch = AppStore['dispatch']
129
127
 
130
128
  // file: src/app/StoreProvider.tsx
131
- 'use client'
129
+ ;('use client')
132
130
 
133
131
  import { useState, type ReactNode } from 'react'
134
132
  import { Provider } from 'react-redux'
@@ -204,7 +202,10 @@ const mapState = (state: { counter: { value: number } }) => ({
204
202
  })
205
203
  const mapDispatch = { increment }
206
204
 
207
- function Counter({ value, increment }: ReturnType<typeof mapState> & typeof mapDispatch) {
205
+ function Counter({
206
+ value,
207
+ increment,
208
+ }: ReturnType<typeof mapState> & typeof mapDispatch) {
208
209
  return <button onClick={() => increment()}>{value}</button>
209
210
  }
210
211
 
@@ -239,7 +240,11 @@ Wrong:
239
240
  import { Provider } from 'react-redux'
240
241
  import { makeStore } from '../lib/store'
241
242
 
242
- export function StoreProvider({ children }: { children: import('react').ReactNode }) {
243
+ export function StoreProvider({
244
+ children,
245
+ }: {
246
+ children: import('react').ReactNode
247
+ }) {
243
248
  const store = makeStore()
244
249
  return <Provider store={store}>{children}</Provider>
245
250
  }
@@ -254,7 +259,11 @@ import { useState } from 'react'
254
259
  import { Provider } from 'react-redux'
255
260
  import { makeStore } from '../lib/store'
256
261
 
257
- export function StoreProvider({ children }: { children: import('react').ReactNode }) {
262
+ export function StoreProvider({
263
+ children,
264
+ }: {
265
+ children: import('react').ReactNode
266
+ }) {
258
267
  const [store] = useState(makeStore)
259
268
  return <Provider store={store}>{children}</Provider>
260
269
  }
@@ -2,11 +2,11 @@
2
2
 
3
3
  ## Decision table
4
4
 
5
- | Environment | Default store shape | Why |
6
- | --- | --- | --- |
7
- | Client-only SPA | One module-level singleton store | There is one browser session and no cross-request leakage risk. |
8
- | SSR-heavy React app | `makeStore()` plus provider-local state | Each request needs its own store instance, but that instance must stay stable across client renders. |
9
- | Non-React integration code | Direct store access can be acceptable | This is outside the React context boundary and should stay out of UI components. |
5
+ | Environment | Default store shape | Why |
6
+ | -------------------------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------- |
7
+ | Client-only SPA | One module-level singleton store | There is one browser session and no cross-request leakage risk. |
8
+ | SSR-heavy React app | `makeStore()` plus provider-local state | Each request needs its own store instance, but that instance must stay stable across client renders. |
9
+ | Non-React integration code | Direct store access can be acceptable | This is outside the React context boundary and should stay out of UI components. |
10
10
 
11
11
  ## SPA pattern
12
12
 
@@ -38,7 +38,7 @@ export const makeStore = () =>
38
38
  })
39
39
 
40
40
  // file: src/app/StoreProvider.tsx
41
- 'use client'
41
+ ;('use client')
42
42
 
43
43
  import { useState, type ReactNode } from 'react'
44
44
  import { Provider } from 'react-redux'
@@ -5,12 +5,12 @@ description: >
5
5
  event-style actions, reducer-owned state transitions, derived data, or a
6
6
  debugging model for Redux Toolkit apps.
7
7
  type: core
8
- library: "@reduxjs/toolkit"
9
- library_version: "2.11.2"
8
+ library: '@reduxjs/toolkit'
9
+ library_version: '2.11.2'
10
10
  sources:
11
- - "reduxjs/redux:docs/tutorials/fundamentals/part-2-concepts-data-flow.md"
12
- - "reduxjs/redux:docs/tutorials/essentials/part-3-data-flow.md"
13
- - "reduxjs/redux:docs/style-guide/style-guide.md"
11
+ - 'reduxjs/redux:docs/tutorials/fundamentals/part-2-concepts-data-flow.md'
12
+ - 'reduxjs/redux:docs/tutorials/essentials/part-3-data-flow.md'
13
+ - 'reduxjs/redux:docs/style-guide/style-guide.md'
14
14
  ---
15
15
 
16
16
  # Redux Dataflow
@@ -134,9 +134,7 @@ const selectFilter = (state: RootState) => state.posts.filter
134
134
  export const selectVisiblePosts = createSelector(
135
135
  [selectPosts, selectFilter],
136
136
  (posts, filter) =>
137
- filter === 'all'
138
- ? posts
139
- : posts.filter((post) => post.published),
137
+ filter === 'all' ? posts : posts.filter((post) => post.published),
140
138
  )
141
139
  ```
142
140
 
@@ -159,7 +157,9 @@ if (post) {
159
157
  Correct:
160
158
 
161
159
  ```ts
162
- store.dispatch(postUpdated({ id: 'p1', changes: { title: 'Changed in place' } }))
160
+ store.dispatch(
161
+ postUpdated({ id: 'p1', changes: { title: 'Changed in place' } }),
162
+ )
163
163
  ```
164
164
 
165
165
  Objects read from the store are still store state; mutating them outside reducers breaks immutability and stale-render assumptions.
@@ -171,7 +171,10 @@ Source: reduxjs/redux:docs/style-guide/style-guide.md
171
171
  Wrong:
172
172
 
173
173
  ```ts
174
- const nextPosts = [...selectPosts(store.getState()), { id: 'p2', title: 'Write docs' }]
174
+ const nextPosts = [
175
+ ...selectPosts(store.getState()),
176
+ { id: 'p2', title: 'Write docs' },
177
+ ]
175
178
  store.dispatch(setPosts(nextPosts))
176
179
  ```
177
180
 
@@ -6,15 +6,15 @@ description: >
6
6
  Toolkit and RTK Query bugs. Covers a practical event -> reducer -> selector ->
7
7
  render debugging loop plus RTK Query cache interpretation.
8
8
  type: lifecycle
9
- library: "@reduxjs/toolkit"
10
- library_version: "2.11.2"
9
+ library: '@reduxjs/toolkit'
10
+ library_version: '2.11.2'
11
11
  requires:
12
12
  - build-modern-redux-apps/redux-dataflow
13
13
  sources:
14
- - "reduxjs/redux:docs/style-guide/style-guide.md"
15
- - "reduxjs/redux:docs/tutorials/essentials/part-5-async-logic.md"
16
- - "reduxjs/redux:docs/tutorials/essentials/part-8-rtk-query-advanced.md"
17
- - "reduxjs/redux-toolkit:docs/usage/usage-guide.md"
14
+ - 'reduxjs/redux:docs/style-guide/style-guide.md'
15
+ - 'reduxjs/redux:docs/tutorials/essentials/part-5-async-logic.md'
16
+ - 'reduxjs/redux:docs/tutorials/essentials/part-8-rtk-query-advanced.md'
17
+ - 'reduxjs/redux-toolkit:docs/usage/usage-guide.md'
18
18
  ---
19
19
 
20
20
  # Debug Redux Toolkit Apps
@@ -6,15 +6,15 @@ description: >
6
6
  createSlice, codemod-assisted RTK 2 updates, and replacing server-data stacks
7
7
  with RTK Query instead of writing new legacy Redux code.
8
8
  type: lifecycle
9
- library: "@reduxjs/toolkit"
10
- library_version: "2.11.2"
9
+ library: '@reduxjs/toolkit'
10
+ library_version: '2.11.2'
11
11
  requires:
12
12
  - build-modern-redux-apps/modern-redux
13
13
  sources:
14
- - "reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx"
15
- - "reduxjs/redux-toolkit:docs/usage/migrating-rtk-2.md"
16
- - "reduxjs/redux-toolkit:packages/rtk-codemods/README.md"
17
- - "reduxjs/redux:docs/style-guide/style-guide.md"
14
+ - 'reduxjs/redux-toolkit:docs/usage/migrating-to-modern-redux.mdx'
15
+ - 'reduxjs/redux-toolkit:docs/usage/migrating-rtk-2.md'
16
+ - 'reduxjs/redux-toolkit:packages/rtk-codemods/README.md'
17
+ - 'reduxjs/redux:docs/style-guide/style-guide.md'
18
18
  ---
19
19
 
20
20
  # Migrate To Modern Redux
@@ -174,8 +174,7 @@ Correct:
174
174
  ```ts
175
175
  configureStore({
176
176
  reducer,
177
- middleware: (getDefaultMiddleware) =>
178
- getDefaultMiddleware().concat(logger),
177
+ middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger),
179
178
  })
180
179
  ```
181
180
 
@@ -5,17 +5,17 @@ description: >
5
5
  layer. Covers createApi, store integration, hooks, invalidation behavior,
6
6
  optimistic updates, and deciding when RTK Query is the right cache model.
7
7
  type: lifecycle
8
- library: "@reduxjs/toolkit"
9
- library_version: "2.11.2"
8
+ library: '@reduxjs/toolkit'
9
+ library_version: '2.11.2'
10
10
  requires:
11
11
  - build-modern-redux-apps/modern-redux
12
12
  sources:
13
- - "reduxjs/redux-toolkit:docs/rtk-query/api/createApi.mdx"
14
- - "reduxjs/redux-toolkit:docs/rtk-query/usage/automated-refetching.mdx"
15
- - "reduxjs/redux-toolkit:docs/rtk-query/usage/manual-cache-updates.mdx"
16
- - "reduxjs/redux-toolkit:docs/rtk-query/usage/persistence-and-rehydration.mdx"
17
- - "reduxjs/redux-toolkit:docs/tutorials/rtk-query.mdx"
18
- - "reduxjs/redux:docs/style-guide/style-guide.md"
13
+ - 'reduxjs/redux-toolkit:docs/rtk-query/api/createApi.mdx'
14
+ - 'reduxjs/redux-toolkit:docs/rtk-query/usage/automated-refetching.mdx'
15
+ - 'reduxjs/redux-toolkit:docs/rtk-query/usage/manual-cache-updates.mdx'
16
+ - 'reduxjs/redux-toolkit:docs/rtk-query/usage/persistence-and-rehydration.mdx'
17
+ - 'reduxjs/redux-toolkit:docs/tutorials/rtk-query.mdx'
18
+ - 'reduxjs/redux:docs/style-guide/style-guide.md'
19
19
  ---
20
20
 
21
21
  # Adopt RTK Query
@@ -315,9 +315,11 @@ import { useAppDispatch } from '../../app/hooks'
315
315
  const dispatch = useAppDispatch()
316
316
 
317
317
  useEffect(() => {
318
- dispatch(api.util.updateQueryData('getPosts', undefined, (draft) => {
319
- draft.push({ id: 'p3', title: 'Patched from component' })
320
- }))
318
+ dispatch(
319
+ api.util.updateQueryData('getPosts', undefined, (draft) => {
320
+ draft.push({ id: 'p3', title: 'Patched from component' })
321
+ }),
322
+ )
321
323
  }, [dispatch])
322
324
  ```
323
325
 
@@ -6,17 +6,17 @@ description: >
6
6
  Immer-backed mutation syntax, slice selectors, getSelectors, injectInto,
7
7
  withLazyLoadedSlices, and current RTK 2 slice patterns.
8
8
  type: core
9
- library: "@reduxjs/toolkit"
10
- library_version: "2.11.2"
9
+ library: '@reduxjs/toolkit'
10
+ library_version: '2.11.2'
11
11
  requires:
12
12
  - model-redux-state/design-state-ownership
13
13
  sources:
14
- - "reduxjs/redux-toolkit:docs/api/createSlice.mdx"
15
- - "reduxjs/redux-toolkit:docs/api/combineSlices.mdx"
16
- - "reduxjs/redux-toolkit:docs/api/createEntityAdapter.mdx"
17
- - "reduxjs/redux-toolkit:docs/usage/immer-reducers.md"
18
- - "reduxjs/redux-toolkit:docs/usage/migrating-rtk-2.md"
19
- - "reduxjs/redux:docs/style-guide/style-guide.md"
14
+ - 'reduxjs/redux-toolkit:docs/api/createSlice.mdx'
15
+ - 'reduxjs/redux-toolkit:docs/api/combineSlices.mdx'
16
+ - 'reduxjs/redux-toolkit:docs/api/createEntityAdapter.mdx'
17
+ - 'reduxjs/redux-toolkit:docs/usage/immer-reducers.md'
18
+ - 'reduxjs/redux-toolkit:docs/usage/migrating-rtk-2.md'
19
+ - 'reduxjs/redux:docs/style-guide/style-guide.md'
20
20
  ---
21
21
 
22
22
  # Build Slices And Selectors
@@ -49,13 +49,19 @@ export const postsSlice = createAppSlice({
49
49
  name: 'posts',
50
50
  initialState,
51
51
  reducers: (create) => ({
52
- postAdded: create.reducer<{ id: string; title: string }>((state, action) => {
53
- state.items.push({ ...action.payload, published: false })
54
- }),
52
+ postAdded: create.reducer<{ id: string; title: string }>(
53
+ (state, action) => {
54
+ state.items.push({ ...action.payload, published: false })
55
+ },
56
+ ),
55
57
  fetchPosts: create.asyncThunk(
56
58
  async () => {
57
59
  const response = await fetch('/api/posts')
58
- return (await response.json()) as { id: string; title: string; published: boolean }[]
60
+ return (await response.json()) as {
61
+ id: string
62
+ title: string
63
+ published: boolean
64
+ }[]
59
65
  },
60
66
  {
61
67
  pending: (state) => {
@@ -145,7 +151,10 @@ const createAppSlice = buildCreateSlice({
145
151
 
146
152
  const usersSlice = createAppSlice({
147
153
  name: 'users',
148
- initialState: { items: [] as { id: string; name: string }[], status: 'idle' as 'idle' | 'pending' | 'failed' },
154
+ initialState: {
155
+ items: [] as { id: string; name: string }[],
156
+ status: 'idle' as 'idle' | 'pending' | 'failed',
157
+ },
149
158
  reducers: (create) => ({
150
159
  fetchUsers: create.asyncThunk(
151
160
  async () => {
@@ -253,7 +262,10 @@ Source: reduxjs/redux-toolkit:docs/usage/immer-reducers.md
253
262
  Wrong:
254
263
 
255
264
  ```ts
256
- export default function todosReducer(state = initialState, action: { type: string; payload?: Todo }) {
265
+ export default function todosReducer(
266
+ state = initialState,
267
+ action: { type: string; payload?: Todo },
268
+ ) {
257
269
  switch (action.type) {
258
270
  case 'todos/todoAdded':
259
271
  return state.concat(action.payload as Todo)
@@ -5,12 +5,12 @@ description: >
5
5
  state, or another external source. Covers state ownership, authority
6
6
  boundaries, slice sizing, and when to move or split data as the app evolves.
7
7
  type: core
8
- library: "@reduxjs/toolkit"
9
- library_version: "2.11.2"
8
+ library: '@reduxjs/toolkit'
9
+ library_version: '2.11.2'
10
10
  sources:
11
- - "reduxjs/redux:docs/style-guide/style-guide.md"
12
- - "reduxjs/redux:docs/tutorials/essentials/part-2-app-structure.md"
13
- - "reduxjs/redux:docs/tutorials/essentials/part-4-using-data.md"
11
+ - 'reduxjs/redux:docs/style-guide/style-guide.md'
12
+ - 'reduxjs/redux:docs/tutorials/essentials/part-2-app-structure.md'
13
+ - 'reduxjs/redux:docs/tutorials/essentials/part-4-using-data.md'
14
14
  ---
15
15
 
16
16
  # Design State Ownership
@@ -110,9 +110,7 @@ const selectPosts = (state: RootState) => state.posts.items
110
110
  const selectVisiblePosts = createSelector(
111
111
  [selectPosts, (_state: RootState, filter: string) => filter],
112
112
  (posts, filter) =>
113
- filter === 'published'
114
- ? posts.filter((post) => post.published)
115
- : posts,
113
+ filter === 'published' ? posts.filter((post) => post.published) : posts,
116
114
  )
117
115
 
118
116
  export function PostsList() {
@@ -160,7 +158,8 @@ Wrong:
160
158
  ```tsx
161
159
  import { useAppSelector } from '../../app/hooks'
162
160
 
163
- const selectDraftTitle = (state: { draft: { title: string } }) => state.draft.title
161
+ const selectDraftTitle = (state: { draft: { title: string } }) =>
162
+ state.draft.title
164
163
 
165
164
  const title = useAppSelector(selectDraftTitle)
166
165
  ```
@@ -190,9 +189,9 @@ function PostsPage() {
190
189
  const [searchParams] = useSearchParams()
191
190
  const dispatch = useAppDispatch()
192
191
 
193
- useEffect(() => {
194
- dispatch(filterChanged(searchParams.get('filter') ?? 'all'))
195
- }, [dispatch, searchParams])
192
+ useEffect(() => {
193
+ dispatch(filterChanged(searchParams.get('filter') ?? 'all'))
194
+ }, [dispatch, searchParams])
196
195
 
197
196
  return null
198
197
  }
@@ -2,12 +2,12 @@
2
2
 
3
3
  ## Choose the owner, then the tool
4
4
 
5
- | Kind of state | Default owner | Typical tool |
6
- | --- | --- | --- |
7
- | Editable form fields | Component | `useState` |
8
- | Shared mutable app data | Redux | Slice state |
9
- | Server cache | RTK Query | `createApi` |
10
- | URL, pathname, search params | Router | Router APIs plus selector inputs |
5
+ | Kind of state | Default owner | Typical tool |
6
+ | ------------------------------------------ | --------------- | ---------------------------------------- |
7
+ | Editable form fields | Component | `useState` |
8
+ | Shared mutable app data | Redux | Slice state |
9
+ | Server cache | RTK Query | `createApi` |
10
+ | URL, pathname, search params | Router | Router APIs plus selector inputs |
11
11
  | Browser-only authority like `localStorage` | External source | Read at boundaries, then dispatch events |
12
12
 
13
13
  ## Good reasons to move data into Redux
@@ -6,15 +6,15 @@ description: >
6
6
  workflows, listener middleware setup, and keeping side effects out of
7
7
  reducers and UI components.
8
8
  type: core
9
- library: "@reduxjs/toolkit"
10
- library_version: "2.11.2"
9
+ library: '@reduxjs/toolkit'
10
+ library_version: '2.11.2'
11
11
  requires:
12
12
  - build-modern-redux-apps/redux-dataflow
13
13
  sources:
14
- - "reduxjs/redux-toolkit:docs/api/createAsyncThunk.mdx"
15
- - "reduxjs/redux-toolkit:docs/api/createListenerMiddleware.mdx"
16
- - "reduxjs/redux:docs/style-guide/style-guide.md"
17
- - "reduxjs/redux:docs/tutorials/essentials/part-5-async-logic.md"
14
+ - 'reduxjs/redux-toolkit:docs/api/createAsyncThunk.mdx'
15
+ - 'reduxjs/redux-toolkit:docs/api/createListenerMiddleware.mdx'
16
+ - 'reduxjs/redux:docs/style-guide/style-guide.md'
17
+ - 'reduxjs/redux:docs/tutorials/essentials/part-5-async-logic.md'
18
18
  ---
19
19
 
20
20
  # Handle Side Effects
@@ -54,8 +54,10 @@ export const store = configureStore({
54
54
  export type RootState = ReturnType<typeof store.getState>
55
55
  export type AppDispatch = typeof store.dispatch
56
56
 
57
- export const startAppListening =
58
- listenerMiddleware.startListening.withTypes<RootState, AppDispatch>()
57
+ export const startAppListening = listenerMiddleware.startListening.withTypes<
58
+ RootState,
59
+ AppDispatch
60
+ >()
59
61
  ```
60
62
 
61
63
  ## Core Patterns
@@ -186,14 +188,17 @@ Correct:
186
188
  ```ts
187
189
  import { createAsyncThunk } from '@reduxjs/toolkit'
188
190
 
189
- const todoSaved = createAsyncThunk('todos/save', async (todo: { id: string }) => {
190
- await fetch('/api/todos', {
191
- method: 'POST',
192
- headers: { 'Content-Type': 'application/json' },
193
- body: JSON.stringify(todo),
194
- })
195
- return todo
196
- })
191
+ const todoSaved = createAsyncThunk(
192
+ 'todos/save',
193
+ async (todo: { id: string }) => {
194
+ await fetch('/api/todos', {
195
+ method: 'POST',
196
+ headers: { 'Content-Type': 'application/json' },
197
+ body: JSON.stringify(todo),
198
+ })
199
+ return todo
200
+ },
201
+ )
197
202
  ```
198
203
 
199
204
  Reducers must stay pure even when Immer is available.
@@ -205,14 +210,13 @@ Source: reduxjs/redux:docs/style-guide/style-guide.md
205
210
  Wrong:
206
211
 
207
212
  ```ts
208
- export const waitForSave = () => async (
209
- _dispatch: unknown,
210
- getState: () => { docs: { status: string } },
211
- ) => {
212
- while (getState().docs.status !== 'saved') {
213
- await new Promise((resolve) => setTimeout(resolve, 100))
213
+ export const waitForSave =
214
+ () =>
215
+ async (_dispatch: unknown, getState: () => { docs: { status: string } }) => {
216
+ while (getState().docs.status !== 'saved') {
217
+ await new Promise((resolve) => setTimeout(resolve, 100))
218
+ }
214
219
  }
215
- }
216
220
  ```
217
221
 
218
222
  Correct:
@@ -2,11 +2,11 @@
2
2
 
3
3
  ## Decision table
4
4
 
5
- | Need | Reach for |
6
- | --- | --- |
7
- | Cached server data | RTK Query |
5
+ | Need | Reach for |
6
+ | ---------------------------------------------------------- | ----------------------------- |
7
+ | Cached server data | RTK Query |
8
8
  | One imperative async workflow with `dispatch` / `getState` | `createAsyncThunk` or a thunk |
9
- | React to later actions or state transitions | `createListenerMiddleware` |
9
+ | React to later actions or state transitions | `createListenerMiddleware` |
10
10
 
11
11
  A good app often mixes imperative and reactive workflows. The split is by job, not by ideology.
12
12
 
@@ -21,6 +21,8 @@ const createRafWithFallbackTimer = (
21
21
  ) => {
22
22
  return (notify: () => void) => {
23
23
  let called = false
24
+ let rafId: number
25
+ let timerId: ReturnType<typeof setTimeout>
24
26
  const callback = () => {
25
27
  if (called) return
26
28
  called = true
@@ -28,8 +30,8 @@ const createRafWithFallbackTimer = (
28
30
  clearTimeout(timerId)
29
31
  notify()
30
32
  }
31
- const rafId = raf(callback)
32
- const timerId = setTimeout(callback, timeout)
33
+ rafId = raf(callback)
34
+ timerId = setTimeout(callback, timeout)
33
35
  }
34
36
  }
35
37
 
@@ -52,7 +54,7 @@ export type AutoBatchOptions =
52
54
  * This can be added to `action.meta` manually, or by using the
53
55
  * `prepareAutoBatched` helper.
54
56
  *
55
- * By default, it will queue a notification for the end of the event loop tick.
57
+ * By default, it will queue a notification using `requestAnimationFrame`.
56
58
  * However, you can pass several other options to configure the behavior:
57
59
  * - `{type: 'tick'}`: queues using `queueMicrotask`
58
60
  * - `{type: 'timer', timeout: number}`: queues using `setTimeout`