Releases: reduxjs/redux
v5.0.1
This patch release adjusts the isPlainObject
util to allow objects created via Object.create(null)
, and fixes a type issue which accidentally made the store state type non-nullable.
What's Changed
- fix(isPlainObject): support check Object.create(null) by @zhe-he in #4633
- fix(types/store): Unexpectedly narrowed return type of function
Store['getState']
by @exuanbo in #4638
Full Changelog: v5.0.0...v5.0.1
v5.0.0
This major release:
- Converts the codebase to TypeScript
- Updates the packaging for better ESM/CJS compatibility and modernizes the build output
- Requires that
action.type
must be a string - Continues to mark
createStore
as deprecated - Deprecates the
AnyAction
type in favor of anUnknownAction
type that is used everywhere - Removes the
PreloadedState
type in favor of a new generic argument for theReducer
type.
This release has breaking changes.
This release is part of a wave of major versions of all the Redux packages: Redux Toolkit 2.0, Redux core 5.0, React-Redux 9.0, Reselect 5.0, and Redux Thunk 3.0.
For full details on all of the breaking changes and other significant changes to all of those packages, see the "Migrating to RTK 2.0 and Redux 5.0" migration guide in the Redux docs.
Note
The Redux core, Reselect, and Redux Thunk packages are included as part of Redux Toolkit, and RTK users do not need to manually upgrade them - you'll get them as part of the upgrade to RTK 2.0. (If you're not using Redux Toolkit yet, please start migrating your existing legacy Redux code to use Redux Toolkit today!)
# RTK
npm install @reduxjs/toolkit
yarn add @reduxjs/toolkit
# Standalone
npm install redux
yarn add redux
Changelog
ESM/CJS Package Compatibility
The biggest theme of the Redux v5 and RTK 2.0 releases is trying to get "true" ESM package publishing compatibility in place, while still supporting CJS in the published package.
The primary build artifact is now an ESM file, dist/redux.mjs
. Most build tools should pick this up. There's also a CJS artifact, and a second copy of the ESM file named redux.legacy-esm.js
to support Webpack 4 (which does not recognize the exports
field in package.json
). Additionally, all of the build artifacts now live under ./dist/
in the published package.
Modernized Build Output
We now publish modern JS syntax targeting ES2020, including optional chaining, object spread, and other modern syntax. If you need to
Build Tooling
We're now building the package using https://github.com/egoist/tsup. We also now include sourcemaps for the ESM and CJS artifacts.
Dropping UMD Builds
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.
We've dropped those build artifacts from the published package, on the grounds that the use cases seem pretty rare today.
There's now a redux.browser.mjs
file in the package that can be loaded from a CDN like Unpkg.
If you have strong use cases for us continuing to include UMD build artifacts, please let us know!
createStore
Marked Deprecated
In Redux 4.2.0, we marked the original createStore
method as @deprecated
. Strictly speaking, this is not a breaking change, nor is it new in 5.0, but we're documenting it here for completeness.
This deprecation is solely a visual indicator that is meant to encourage users to migrate their apps from legacy Redux patterns to use the modern Redux Toolkit APIs.
The deprecation results in a visual strikethrough when imported and used, like , but with no runtime errors or warnings.createStore
createStore
will continue to work indefinitely, and will not ever be removed. But, today we want all Redux users to be using Redux Toolkit for all of their Redux logic.
To fix this, there are three options:
- Follow our strong suggestion to switch over to Redux Toolkit and
configureStore
- Do nothing. It's just a visual strikethrough, and it doesn't affect how your code behaves. Ignore it.
- Switch to using the
legacy_createStore
API that is now exported, which is the exact same function but with no@deprecated
tag. The simplest option is to do an aliased import rename, likeimport { legacy_createStore as createStore } from 'redux'
Action types must be strings
We've always specifically told our users that actions and state must be serializable, 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.
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.
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.
TypeScript Changes
We've dropped support for TS 4.6 and earlier, and our support matrix is now TS 4.7+.
Typescript rewrite
In 2019, we began a community-powered conversion of the Redux codebase to TypeScript. The original effort was discussed in #3500: Port to TypeScript, and the work was integrated in PR #3536: Convert to TypeScript.
However, the TS-converted code sat around in the repo for several years, unused and unpublished, due to concerns about possible compatibility issues with the existing ecosystem (as well as general inertia on our part).
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.
Please report any unexpected compatibility issues!!
AnyAction
deprecated in favour of UnknownAction
The Redux TS types have always exported an AnyAction
type, which is defined to have {type: string}
and treat any other field as any
. This makes it easy to write uses like console.log(action.whatever)
, but unfortunately does not provide any meaningful type safety.
We now export an UnknownAction
type, which treats all fields other than action.type
as unknown
. This encourages users to write type guards that check the action object and assert its specific TS type. Inside of those checks, you can access a field with better type safety.
UnknownAction
is now the default any place in the Redux source that expects an action object.
AnyAction
still exists for compatibility, but has been marked as deprecated.
Note that Redux Toolkit's action creators have a .match()
method that acts as a useful type guard:
if (todoAdded.match(someUnknownAction)) {
// action is now typed as a PayloadAction<Todo>
}
You can also use the new isAction
util to check if an unknown value is some kind of action object.
Middleware
type changed - Middleware action
and next
are typed as unknown
Previously, the next
parameter is typed as the D
type parameter passed, and action
is typed as the Action
extracted from the dispatch type. Neither of these are a safe assumption:
next
would be typed to have all of the dispatch extensions, including the ones earlier in the chain that would no longer apply.- Technically it would be mostly safe to type
next
as the default Dispatch implemented by the base redux store, however this would causenext(action)
to error (as we cannot promiseaction
is actually anAction
) - and it wouldn't account for any following middlewares that return anything other than the action they're given when they see a specific action.
- Technically it would be mostly safe to type
action
is not necessarily a known action, it can be literally anything - for example a thunk would be a function with no.type
property (soAnyAction
would be inaccurate)
We've changed next
to be (action: unknown) => unknown
(which is accurate, we have no idea what next
expects or will return), and changed the action
parameter to be unknown
(which as above, is accurate).
In order to safely interact with values or access fields inside of the action
argument, you must first do a type guard check to narrow the type, such as isAction(action)
or someActionCreator.match(action)
.
This new type is incompatible with the v4 Middleware
type, so if a package's middleware is saying it's incompatible, check which version of Redux it's getting its types from!
PreloadedState
type removed in favour of Reducer
generic
We've made tweaks to the TS types to improve type safety and behavior.
First, the Reducer
type now has a PreloadedState
possible generic:
type Reducer<S, A extends Action, PreloadedState = S> = (
state: S | PreloadedState | undefined,
action: A
) => S
Per the explanation in #4491:
Why the need for this change? When the store is first created by createStore
/configureStore
, the initial state is set to whatever is passed as the preloadedState
argument (or undefined
if nothing is passed). That means that the first time that the reducer is called, it is called with the preloadedState
. After the first call, the reducer is always passed the current state (which is S
).
For most normal reducers, S | undefined
accurately describes what can be passed in for the preloadedState
. However the combineReducers
function allows for a preloaded state of Partial<S> | undefined
.
The solution is to have a separate generic that represents wha...
v5.0.0-rc.1
This release candidate adds a new isAction
predicate that can be used as a TS type guard, and exports the existing internal isPlainObject
util.
Note that we hope to release Redux Toolkit 2.0, Redux core 5.0, and React-Redux 9.0 by the start of December! (If we don't hit that, we'll aim for January, after the holidays.)
See the preview Redux Toolkit 2.0 + Redux core 5.0 Migration Guide for an overview of breaking changes in RTK 2.0 and Redux core.
npm install redux@next
yarn add redux@next
Changes
isAction
Predicate
We recently added an isAction
predicate to RTK, then realized it's better suited for the Redux core. This can be used anywhere you have a value that could be a Redux action object, and you need to check if it is actually an action. This is specifically useful for use with the updated Redux middleware TS types, where the default value is now unknown
and you need to use a type guard to tell TS that the current value is actually an action:
We've also exported the isPlainObject
util that's been in the Redux codebase for years as well.
What's Changed
- Add isAction type predicate by @EskiMojo14 in #4620
- export isPlainObject by @EskiMojo14 in #4621
- Update build tooling for 5.0 by @markerikson in #4623
Full Changelog: v5.0.0-rc.0...v5.0.0-rc.1
v5.0.0-rc.0
This release candidate has no actual source code changes since the previous v5.0.0-beta.0
release.
Note that we hope to release Redux Toolkit 2.0, Redux core 5.0, and React-Redux 9.0 by the start of December! (If we don't hit that, we'll aim for January, after the holidays.)
See the preview Redux Toolkit 2.0 + Redux core 5.0 Migration Guide for an overview of breaking changes in RTK 2.0 and Redux core.
npm install redux@next
yarn add redux@next
Full Changelog: v5.0.0-beta.0...v5.0.0-rc.0
v5.0.0-beta.0
This beta release alters our TS types to add and use a new UnknownAction
type where possible for better type safety, and includes all prior changes from the 5.0 alphas. This release has breaking changes from 4.x.
We recommend that users should prefer using Redux Toolkit for Redux development, and use the RTK 2.0 beta that depends on this core release, rather than using the Redux core library directly
npm i redux@next
yarn add redux@next
Changelog
New UnknownAction
Type
The Redux TS types have always exported an AnyAction
type, which is defined to have {type: string}
and treat any other field as any
. This makes it easy to write uses like console.log(action.whatever)
, but unfortunately does not provide any meaningful type safety.
We now export an UnknownAction
type, which treats all fields other than action.type
as unknown
. This encourages users to write type guards that check the action object and assert its specific TS type. Inside of those checks, you can access a field with better type safety.
UnknownAction
is now the default any place in the Redux source that expects an action object.
AnyAction
still exists for compatibility, but has been marked as deprecated.
Note that Redux Toolkit's action creators have a .match()
method that acts as a useful type guard:
if (todoAdded.match(someUnknownAction)) {
// action is now typed as a PayloadAction<Todo>
}
Earlier Alpha Changes
Summarizing changes from the earlier 5.0-alpha
releases:
- Source code converted to TS
createStore
deprecation tag ported- Removed
isMinified
check - Packaging converted to have full ESM/CJS compatibility
- Dropped UMD build artifacts
- JS build output is now "modern" and not transpiled for IE11 compatibility
- Listener subscriptions are now a
Set
- Store enhancer types improved
Reducer
type accepts aPreloadedState
generic- Middleware
action
andnext
are typed asunknown
action.type
field must be a string
What's Changed
- Prefer use of Action or UnknownAction instead of AnyAction by @EskiMojo14 in #4520
Full Changelog: v5.0.0-alpha.6...v5.0.0-beta.0
v5.0.0-alpha.6
This is an alpha release for Redux 5.0, and has breaking changes. It changes store.dispatch
to require that action.type
must always be a string.
Changelog
Action Types Must Be Strings
We've always specifically told our users that actions and state must be serializable, 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.
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.
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.
TS Support Updated
We've updated our supported TS version matrix to be TS 4.7 and higher.
What's Changed
- Change TS tests to only be 4.7 onwards by @EskiMojo14 in #4545
- Require action types to be strings by @EskiMojo14 in #4544
Full Changelog: v5.0.0-alpha.5...v5.0.0-alpha.6
v5.0.0-alpha.5
This is an alpha release for Redux 5.0. This release has has breaking types changes.
npm i redux@alpha
yarn add redux@alpha
Changelog
Reducer
type and PreloadedState
generic
We've made tweaks to the TS types to improve type safety and behavior. There are two big types changes in this alpha.
First, the Reducer
type now has a PreloadedState
possible generic:
type Reducer<S, A extends Action, PreloadedState = S> = (
state: S | PreloadedState | undefined,
action: A
) => S
Per the explanation in #4491 :
Why the need for this change? When the store is first created by createStore
, the initial state is set to whatever is passed as the preloadedState
argument (or undefined
if nothing is passed). That means that the first time that the reducer is called, it is called with the preloadedState
. After the first call, the reducer is always passed the current state (which is S
).
For most normal reducers, S | undefined
accurately describes what can be passed in for the preloadedState
. However the combineReducers
function allows for a preloaded state of Partial<S> | undefined
.
The solution is to have a separate generic that represents what the reducer accepts for its preloaded state. That way createStore
can then use that generic for its preloadedState
argument.
Previously, this was handled by a $CombinedState
type, but that complicated things and led to some user-reported issues. This removes the need for $CombinedState
altogether.
This change does include some breaking changes, but overall should not have a huge impact on users upgrading in user-land:
- The
Reducer
,ReducersMapObject
, andcreateStore
types/function take an additionalPreloadedState
generic which defaults toS
. - The overloads for
combineReducers
are removed in favor of a single function definition that takes theReducersMabObject
as its generic parameter. Removing the overloads was necessary with these changes, since sometimes it was choosing the wrong overload. - Enhancers that explicitly list the generics for the reducer will need to add the third generic.
Middleware action
and next
are typed as unknown
Currently, the next
parameter is typed as the D
type parameter passed, and action
is typed as theAction
extracted from the dispatch type. Neither of these are a safe assumption:
next
would be typed to have all of the dispatch extensions, including the ones earlier in the chain that would no longer apply.- Technically it would be mostly safe to type
next
as the default Dispatch implemented by the base redux store, however this would causenext(action)
to error (as we cannot promiseaction
is actually anAction
) - and it wouldn't account for any following middlewares that return anything other than the action they're given when they see a specific action.
- Technically it would be mostly safe to type
action
is not necessarily a known action, it can be literally anything - for example a thunk would be a function with no .type property (soAnyAction
would be inaccurate)
We've changed next
to be (action: unknown) => unknown
(which is accurate, we have no idea what next
expects or will return), and changes the action
parameter to be unknown
(which as above, is accurate).
What's Changed
- Type-check tests by @Methuselah96 in #4489
- Add PreloadedState generic by @Methuselah96 in #4491
- Type action and next as unknown by @EskiMojo14 in #4519
Full Changelog: v5.0.0-alpha.4...v5.0.0-alpha.5
v5.0.0-alpha.4
This is an alpha release for Redux 5.0. This release has many changes to our build setup and published package contents, and has breaking changes.
npm i redux@alpha
yarn add redux@alpha
Changelog
ESM/CJS Package Compatibility
The biggest theme of the Redux v5 and RTK 2.0 releases is trying to get "true" ESM package publishing compatibility in place, while still supporting CJS in the published package.
Earlier alphas made changes to the package.json
contents and published build artifacts in an attempt to get ESM+CJS compat working correctly, but those alphas had several varying compat issues.
We've set up a battery of example applications in the RTK repo that use a variety of build tools (currently CRA4, CRA5, Next 13, and Vite, Node CJS mode, and Node ESM mode), to verify that Redux and Redux Toolkit compile, import, and run correctly with both TS and various bundlers. We've also set up a check using a custom CLI wrapper around https://arethetypeswrong.github.io to check for potential packaging incompatibilities.
This release changes the names and contents of the published build artifacts, and the various exports/module/main
fields in package.json
to point to those.
The primary build artifact is now an ESM file, dist/redux.mjs
. Most build tools should pick this up. There's also a CJS artifact, and a second copy of the ESM file named redux.legacy-esm.js
to support Webpack 4 (which does not recognize the exports
field in package.json
).
As of this release, we think we have ESM+CJS compat working correctly, but we ask that the community try out the alphas in your apps and let us know of any compat problems!
Note: The one known potential issue is that TypeScript's new
moduleResolution: "node16"
mode may see a mismatch between the ESM artifacts and the TS typedefs when imported in a Node CJS environment, and [that may allow hypothetically-incorrect import usage. (See ongoing discussion in https://github.com/arethetypeswrong/arethetypeswrong.github.io/issues/21 .) In practice, we think that probably won't be a concern, and we'll do further investigation before a final release.
Build Tooling
We're now building the package using https://github.com/egoist/tsup . It looks like the output is effectively equivalent, but please let us know if there's any issues.
We also now include sourcemaps for the ESM and CJS artifacts.
Dropping UMD Builds
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.
For now, we're dropping those build artifacts from the published package, on the grounds that the use cases seem pretty rare today.
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.
If you have strong use cases for us continuing to include UMD build artifacts, please let us know!
What's Changed
- Build package in prepack instead of prepublish by @Methuselah96 in #4493
- Rewrite build/setup and hopefully fix ESM compat by @markerikson in #4511
- Support Webpack 4 with a "legacy ESM" artifact by @markerikson in #4512
Full Changelog: v5.0.0-alpha.2...v5.0.0-alpha.4
v5.0.0-alpha.2
This is an alpha release for Redux 5.0. This release has types changes, an internal implementation tweak, and many changes to our build and test setup.
Changelog
Store Enhancer TS Types Changes
The TS conversion in 2019 had made some changes to the definition of the StoreEnhancer
TS type around replacing reducers. Some time later, we concluded that the enhancer types changes needed to be reverted, but that fell by the wayside. We've finally merged that reversion. This earlier type was never actually released publicly.
We also made an additional change to improve the typing of the next
arg in enhancers.
Internal Listener Implementation
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.
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.
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.
Build Tooling Updates
We made numerous updates to our build tooling, including switching package management to Yarn 3, running tests directly from src
locally instead of building first, actually running the TS typetests we'd added years ago, testing our types against a matrix of TS versions, and running tests in CI against a built copy of the library.
What's Changed
- Replace listeners array with a Map for better performance by @markerikson in #4476
- Revert adding the store as a return type to replaceReducer by @Methuselah96 in #3772
- Run tests from source instead of building first by @markerikson in #4483
- Fix type of next parameter in StoreEnhancer type by @Methuselah96 in #3776
- Enable strict mode for TypeScript tests by @Methuselah96 in #4484
- Convert repo to use Yarn 3 for package management by @markerikson in #4485
Full Changelog: v5.0.0-alpha.1...v5.0.0-alpha.2
v5.0.0-alpha.1
This is an alpha release for Redux 5.0. This release has breaking changes.
Changelog
ESM Migration
As part of the Redux Toolkit 2.0 alpha development work, we've migrated the redux
core package definition to be a full {type: "module"}
ESM package with an exports
field (with CJS still included for compatibility purposes).
We've done local testing of the package, but we ask the community to try out this alpha in your own projects and report any breakages you find!
Build Artifact Modernization
We've updated the build output in several ways:
- Build output is no longer transpiled! Instead we target modern JS syntax
- Updated to the latest Rollup 3.x
- Dropped the UMD build artifacts (if you have use cases for these, please let us know!)
- Moved all build artifacts to live under
./dist/
, instead of separate top-level folders
Ported Changes from 4.x
We've ported the @deprecated
marker for createStore
and added legacy_createStore
from Redux 4.2.0. Please use Redux Toolkit's configureStore()
instead, as well as the rest of Redux Toolkit's APIs.
The isMinified
debug check has been removed.
Other Changes
The "valid reducer" check is done earlier to fix an edge case.
What's Changed
- Upgraded eslint and eslint plugins by @madiweaver in #4255
- Fixed build script by upgrading rollup-plugin-typescript2 to latest by @madiweaver in #4256
- Removed deprecated packages by upgrading @babel/cli to version 7.16.7 by @madiweaver in #4258
- Revamp
rollup.config.js
by @xty in #4311 - change reducer type validation place by @Ahmed-Hakeem in #4452
- Port
createStore
deprecation andisMinified
removal from 4.x branch by @markerikson in #4473 - Migrate Redux package to be full ESM by @markerikson in #4474
Full Changelog: v5.0.0-alpha.0...v5.0.0-alpha.1