Skip to content

Commit 7804bc6

Browse files
committed
Edits and reshuffling of content for the "Migrations" page
1 parent db64458 commit 7804bc6

File tree

2 files changed

+47
-40
lines changed

2 files changed

+47
-40
lines changed

docs/migrations/1.x-to-2.x.md

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
2-
id: 1.x-to-2.x
3-
title: 1.x → 2.x
4-
sidebar_label: 1.x → 2.x
2+
id: migrating-1.x-to-2.x
3+
title: Migrating 1.x → 2.x
4+
sidebar_label: Migrating 1.x → 2.x
55
hide_title: true
66
toc_max_heading_level: 4
77
---
@@ -10,33 +10,31 @@ toc_max_heading_level: 4
1010

1111
<div className="migration-guide">
1212

13-
# 1.x → 2.x
13+
# Migrating 1.x → 2.x
1414

1515
## Introduction
1616

17-
<!-- TODO: some blurb here about how cool 2.0 is -->
17+
Redux Toolkit has been available since 2019, and today it's the standard way to write Redux apps. We've gone 4+ years without any breaking changes. Now, RTK 2.0 gives us a chance to modernize the packaging, clean up deprecated options, and tighten up some edge cases.
1818

19-
## Breaking Changes
20-
21-
### Core, Toolkit and React Redux
22-
23-
#### Action types _must_ be strings
19+
Redux Toolkit 2.0 is accompanied by major versions of all the other Redux packages: Redux core 5.0, React-Redux 9.0, Redux Thunk 3.0, and Reselect 5.0.
2420

25-
We've always specifically told our users that [actions and state _must_ be serializable](https://redux.js.org/style-guide/#do-not-put-non-serializable-values-in-state-or-actions), and that `action.type` _should_ be a string. This is both to ensure that actions are serializable, and to help provide a readable action history in the Redux DevTools.
21+
This page lists known potentially breaking changes in Redux Toolkit 2.0 and Redux core 5.0, as well as new features in Redux Toolkit 2.0. As a reminder, you should not need to actually install or use the core `redux` package directly - RTK wraps that, and re-exports all methods and types.
2622

27-
`store.dispatch(action)` now specifically enforces that `action.type` _must_ be a string and will throw an error if not, in the same way it throws an error if the action is not a plain object.
23+
In practice, **most of the "breaking" changes should not have an actual effect on end users**. The changes most likely to need app code updates are:
2824

29-
In practice, this was already true 99.99% of the time and shouldn't have any effect on users (especially those using Redux Toolkit and `createSlice`), but there may be some legacy Redux codebases that opted to use Symbols as action types.
25+
- [Object syntax removed for `createReducer` and `createSlice.extraReducers`](#object-syntax-for-createsliceextrareducers-and-createreducer-removed)
26+
- [`configureStore.middleware` must be a callback](#configurestoremiddleware-must-be-a-callback)
27+
- [`Middleware` type changed - Middleware `action` and `next` are typed as `unknown`](#middleware-type-changed---middleware-action-and-next-are-typed-as-unknown)
3028

31-
#### Dropping UMD builds
29+
## Packaging Changes (all)
3230

33-
Redux has always shipped with UMD build artifacts. These are primarily meant for direct import as script tags, such as in a CodePen or a no-bundler build environment.
31+
We've made updates to the build packaging for all of the Redux-related libraries. These are technically "breaking", but _should_ be transparent to end users, and actually enable better support for scenarios such as using Redux via ESM files under Node.
3432

35-
For now, we're dropping those build artifacts from the published package, on the grounds that the use cases seem pretty rare today.
33+
#### Addition of `exports` field in `package.json`
3634

37-
We do have a browser-ready ESM build artifact included at dist/redux.browser.mjs, which can be loaded via a script tag that points to that file on Unpkg.
35+
We've migrated the package definitions to include the `exports` field for defining which artifacts to load, with a modern ESM build as the primary artifact (with CJS still included for compatibility purposes).
3836

39-
If you have strong use cases for us continuing to include UMD build artifacts, please let us know!
37+
We've done local testing of the package, but we ask the community to try out this in your own projects and report any breakages you find!
4038

4139
#### Build Artifact Modernization
4240

@@ -46,23 +44,27 @@ We've updated the build output in several ways:
4644
- Moved all build artifacts to live under ./dist/, instead of separate top-level folders
4745
- The lowest Typescript version we test against is now 4.7
4846

49-
#### Addition of `exports` field in `package.json`
47+
#### Dropping UMD builds
48+
49+
Redux has always shipped with UMD build artifacts. These are primarily meant for direct import as script tags, such as in a CodePen or a no-bundler build environment.
5050

51-
We've migrated the package definitions to be a full `{type: "module"}` ESM package with an `exports` field (with CJS still included for compatibility purposes).
51+
For now, we're dropping those build artifacts from the published package, on the grounds that the use cases seem pretty rare today.
5252

53-
We've done local testing of the package, but we ask the community to try out this in your own projects and report any breakages you find!
53+
We do have a browser-ready ESM build artifact included at `dist/$PACKAGE_NAME.browser.mjs`, which can be loaded via a script tag that points to that file on Unpkg.
5454

55-
#### Error message extraction
55+
If you have strong use cases for us continuing to include UMD build artifacts, please let us know!
5656

57-
Redux 4.1.0 optimized its bundle size by [extracting error message strings out of production builds](https://github.com/reduxjs/redux/releases/tag/v4.1.0), based on React's approach. We've applied the same technique to RTK. This saves about 1000 bytes from prod bundles (actual benefits will depend on which imports are being used).
57+
## Breaking Changes
58+
59+
### Core
5860

59-
#### Internal listener implementation
61+
#### Action types _must_ be strings
6062

61-
The Redux store has always used an array to track listener callbacks, and used `listeners.findIndex` to remove listeners on unsubscribe. As we found in React Redux, that can have perf issues when many listeners are unsubscribing at once.
63+
We've always specifically told our users that [actions and state _must_ be serializable](https://redux.js.org/style-guide/#do-not-put-non-serializable-values-in-state-or-actions), and that `action.type` _should_ be a string. This is both to ensure that actions are serializable, and to help provide a readable action history in the Redux DevTools.
6264

63-
In React Redux, we fixed that with a more sophisticated linked list approach. Here, we've updated the listeners to be stored in a `Map` instead, which has better delete performance than an array.
65+
`store.dispatch(action)` now specifically enforces that `action.type` _must_ be a string and will throw an error if not, in the same way it throws an error if the action is not a plain object.
6466

65-
In practice this shouldn't have any real effect, because React Redux sets up a subscription in `<Provider>`, and all nested components subscribe to that. But, nice to fix it here as well.
67+
In practice, this was already true 99.99% of the time and shouldn't have any effect on users (especially those using Redux Toolkit and `createSlice`), but there may be some legacy Redux codebases that opted to use Symbols as action types.
6668

6769
<div class="typescript-only">
6870

@@ -72,7 +74,7 @@ In 2019, we began a community-powered conversion of the Redux codebase to TypeSc
7274

7375
However, the TS-converted code in master has sat around since then, unused and unpublished, due to concerns about possible compatibility issues with the existing ecosystem (as well as general inertia on our part).
7476

75-
Redux core v5 is now built from that converted source code. In theory, this should be almost identical in both runtime behavior and types to the 4.x build, but it's very likely that some of the changes may cause types issues.
77+
Redux core v5 is now built from that TS-converted source code. In theory, this should be almost identical in both runtime behavior and types to the 4.x build, but it's very likely that some of the changes may cause types issues.
7678

7779
Please report any unexpected compatibility issues on [Github](https://github.com/reduxjs/redux/issues)!
7880

@@ -305,6 +307,10 @@ const customCreateApi = buildCreateApi(
305307
)
306308
```
307309

310+
#### Error message extraction
311+
312+
Redux 4.1.0 optimized its bundle size by [extracting error message strings out of production builds](https://github.com/reduxjs/redux/releases/tag/v4.1.0), based on React's approach. We've applied the same technique to RTK. This saves about 1000 bytes from prod bundles (actual benefits will depend on which imports are being used).
313+
308314
<div class="typescript-only">
309315

310316
#### Non-default middleware/enhancers must use `Tuple`
@@ -338,9 +344,9 @@ If you prefer to assume that the lookups _might_ be undefined, use TypeScript's
338344

339345
</div>
340346

341-
## Features
347+
## New Features
342348

343-
<!-- TODO: some blurb here about how new features are only in toolkit(?) -->
349+
These features are new in Redux Toolkit 2.0, and help cover additional use cases that we've seen users ask for in the ecosystem.
344350

345351
### `combineSlices` API with slice reducer injection for code-splitting
346352

@@ -445,7 +451,7 @@ expect(selectSlice(customState)).toBe(slice.getInitialState())
445451
expect(selectMultiple(customState, 2)).toBe(slice.getInitialState() * 2)
446452
```
447453

448-
### Callback syntax for `createSlice.reducers`
454+
### `createSlice.reducers` callback syntax and thunk support
449455

450456
One of the oldest feature requests we've had is the ability to declare thunks directly inside of `createSlice`. Until now, you've always had to declare them separately, give the thunk a string action prefix, and handle the actions via `createSlice.extraReducers`:
451457

@@ -484,9 +490,9 @@ We've _wanted_ to include a way to define thunks directly inside of `createSlice
484490

485491
We've settled on these compromises:
486492

493+
- **In order to create async thunks with `createSlice`, you specifically need to [set up a custom version of `createSlice` that has access to `createAsyncThunk`](../api/createSlice#createasyncthunk)**.
487494
- You can declare thunks inside of `createSlice.reducers`, by using a "creator callback" syntax for the `reducers` field that is similar to the `build` callback syntax in RTK Query's `createApi` (using typed functions to create fields in an object). Doing this does look a bit different than the existing "object" syntax for the `reducers` field, but is still fairly similar.
488495
- You can customize _some_ of the types for thunks inside of `createSlice`, but you _cannot_ customize the `state` or `dispatch` types. If those are needed, you can manually do an `as` cast, like `getState() as RootState`.
489-
- In order to create async thunks with `createSlice`, you specifically need to [set up a version that uses `createAsyncThunk`](../api/createSlice#createasyncthunk).
490496

491497
In practice, we hope these are reasonable tradeoffs. Creating thunks inside of `createSlice` has been widely asked for, so we think it's an API that will see usage. If the TS customization options are a limitation, you can still declare thunks outside of `createSlice` as always, and most async thunks don't need `dispatch` or `getState` - they just fetch data and return. And finally, setting up a custom `createSlice` allows you to opt into `createAsyncThunk` being included in your bundle size (though it may already be included if used directly or as part of RTK Query - in either of these cases there's no _additional_ bundle size).
492498

@@ -554,7 +560,7 @@ export const { addTodo, deleteTodo, fetchTodo } = todosSlice.actions
554560

555561
#### Codemod
556562

557-
Using the new callback syntax is entirely optional (the object syntax is still standard), but an existing slice would need to be converted before it can take advantage of the new capabilities this syntax provides. To make this easier, a [codemod](../api/codemods) is provided.
563+
**Using the new callback syntax is entirely optional (the object syntax is still standard)**, but an existing slice would need to be converted before it can take advantage of the new capabilities this syntax provides. To make this easier, a [codemod](../api/codemods) is provided.
558564

559565
```sh
560566
npx @reduxjs/rtk-codemods createSliceReducerBuilder ./src/features/todos/slice.ts
@@ -593,7 +599,7 @@ We've updated `configureStore` to add the `autoBatchEnhancer` to the store setup
593599

594600
[`entityAdapter.getSelectors()`](../api/createEntityAdapter#selector-functions) now accepts an options object as its second argument. This allows you to pass in your own preferred `createSelector` method, which will be used to memoize the generated selectors. This could be useful if you want to use one of Reselect's new alternate memoizers, or some other memoization library with an equivalent signature.
595601

596-
### New dev checks in `reselect` v5
602+
### New dev checks in Reselect v5
597603

598604
Reselect v5 includes a dev-only check to check stability of input selectors, by running them an extra time with the same parameters, and checking that the result matches.
599605

@@ -791,7 +797,7 @@ const todoSlice = createSlice({
791797
export const { selectTodosByAuthor } = todoSlice.selectors
792798
```
793799

794-
With `reselect`'s default cache size of 1, this can cause caching issues if called in multiple components with different arguments. One typical solution for this (without `createSlice`) is a [selector factory](https://redux.js.org/usage/deriving-data-selectors#creating-unique-selector-instances):
800+
With `createSelector`'s default cache size of 1, this can cause caching issues if called in multiple components with different arguments. One typical solution for this (without `createSlice`) is a [selector factory](https://redux.js.org/usage/deriving-data-selectors#creating-unique-selector-instances):
795801

796802
```ts
797803
export const makeSelectTodosByAuthor = () =>

website/sidebars.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@
66
"collapsed": false,
77
"items": ["introduction/getting-started"]
88
},
9-
{
10-
"type": "category",
11-
"label": "Migrations",
12-
"items": ["migrations/1.x-to-2.x"]
13-
},
9+
1410
{
1511
"type": "category",
1612
"label": "Tutorials",
@@ -27,6 +23,11 @@
2723
"label": "Using Redux Toolkit",
2824
"collapsed": false,
2925
"items": [
26+
{
27+
"type": "category",
28+
"label": "Migrations",
29+
"items": ["migrations/migrating-1.x-to-2.x"]
30+
},
3031
"usage/usage-guide",
3132
"usage/usage-with-typescript",
3233
"usage/immer-reducers"

0 commit comments

Comments
 (0)