NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #1523 most downloaded on npm
Official React bindings for Redux
Last release 6 days ago
29 Sep 2026
Ships unpredictably
gaps range from 2 weeks to 1.4 years
Nearly every release is documented
notes for 60 of the last 60 stable releases
7 versions withdrawn
withdrawn after publishing
11 years old
145 releases · first in 2015
This alpha release fixes two bugs in useSignalSelector : stale values rendered in the gap between a dispatch and the store notification, and tracking
This alpha release fixes two bugs in useSignalSelector: stale values rendered in the gap between a dispatch and the store notification, and tracking proxies leaking out of values a selector held onto from an earlier run. It also cuts the cost of spreading or enumerating objects inside selectors, and adds test coverage for using useSignalSelector with RTK Query's hooks. The stock Provider and useSelector are unchanged.
npm install react-redux@alphaThis is still an alpha. Please try it out and give us feedback! The alpha.0 notes cover what useSignalSelector is and how to opt in.
Once a useSignalSelector hook had its full dependency graph built, its getSnapshot returned a cached result that only updated when the store notified subscribers. Normally that happens synchronously inside dispatch(), but there are several cases where React renders the component before that notification arrives:
configureStore includes the autoBatchEnhancer, which delays notifications for batched actions (like RTK Query's pending and fulfilled actions) until the next animation frameuseSelector component and a useSignalSelector component in the same tree render in the same passIn all of these, useSignalSelector could render the previous value, and a useSelector and a useSignalSelector reading the same field could disagree within one render.
getSnapshot now checks whether store.getState() has moved since the cached result was computed. If it has, it re-runs the selector against the current state. useSignalSelector also now passes React a new getSnapshot when the selector reference changes, matching useSelector, so React's post-commit consistency check runs in the same cases it does for useSelector.
The render-time fallback path above runs the selector against raw state, and we assumed its result could never contain tracking proxies. That assumption was wrong. A selector that holds onto a value from an earlier tracked run, via a closure or a ref, can return a proxy from that earlier run.
RTK Query does exactly this: its query hooks keep the last result so they can show the previous data while a new arg loads. With a stable selectFromResult, the component received a proxy of the previous data during that window instead of the raw state object. Results from that path are now unwrapped the same way as the main path.
Spreading an object in a selector ({ ...state.user }), or using Object.keys/values/entries, Object.assign, JSON.stringify, or for...in, previously recorded a dependency on the object's key list plus one dependency per field. Reading every field of an immutably-updated object is equivalent to depending on the object's identity, so a full enumeration of a nested object now collapses into a single identity dependency on that object.
Partial enumerations still track precisely: Object.keys(obj).length, or reading only some fields after enumerating, keeps field-level dependencies. The root state object and arrays are excluded, since their tracking already works differently.
This mostly shows up with RTK Query, whose selectors spread each cache entry. In our RTK Query benchmark, useSignalSelector time per dispatch dropped by about 20-30%.
We've added an interop test suite that runs RTK Query's hooks on top of useSignalSelector, via a custom createApi:
import {
buildCreateApi,
coreModule,
reactHooksModule,
} from '@reduxjs/toolkit/query/react'
import { useDispatch, useSignalSelector, useStore } from 'react-redux'
export const createApi = buildCreateApi(
coreModule(),
reactHooksModule({
hooks: { useDispatch, useSelector: useSignalSelector, useStore },
}),
)The tests cover query phases, selectFromResult, mutations and invalidation, skip, arg changes, and render counts, which match useSelector exactly. The types line up too: useSignalSelector satisfies the hooks.useSelector option type with no casts.
Writing those tests turned up two bugs on the RTK side, both fixed in RTK 2.13.0. useQueryState passed a new inline selector to useSelector on every render, which forced useSignalSelector to re-run the full tracked selector on every render. It also let isSuccess flip on unrelated re-renders during a refetch after an error. With 2.13.0, useSignalSelector selector runs per dispatch in our RTK Query benchmark showed a ~30% drop vs alpha.2. We recommend 2.13.0+ if you try this setup.
10 s per scenario, this release vs 9.3.0, Chrome, react-dom/profiling, RTK 2.12.
| Scenario | Script | Blocked | Notes |
|---|---|---|---|
| tree-view | -54% | -77% | |
| many-components-many-slices | -31% | -54% | |
| realistic-slice-count | -27% | -80% | |
| deeptree-nested-hooks | -24% | -61% | |
| entity-list | -22% | -45% | |
| rapid-dispatch | -21% | -65% | |
| multi-selector-component | -20% | -82% | |
| price-ticker | -19% | -58% | stock drops frames |
| selective-update | -15% | -64% | |
| forms | -12% | -80% | |
| entity-list-array | -9% | -62% | |
| many-components-same-slice | +3% | +96% | flat; work moved into dispatch |
| rtkq-separate-queries | +4% | +21% | |
| one-component-many-slices | +28% | +32% | 20,000 top-level keys |
| derived-selectors | +53% | +144% |
Render counts match 9.3.0 within noise, except where stock drops frames under load.
rtkq-separate-queries moved from +9% in alpha.1 to +4%. derived-selectors and one-component-many-slices remain the two scenarios where useSignalSelector is slower than useSelector. Their numbers vary a lot between runs, and before/after runs of this release's changes showed no measurable difference for either.
Full Changelog: v9.4.0-alpha.1...v9.4.0-alpha.2
One column per quarter.
This alpha release fixes a bug where useSignalSelector stopped updating when a memoized Reselect selector was shared between components or called with
This alpha release fixes a bug where useSignalSelector stopped updating when a memoized Reselect selector was shared between components or called with the same state twice, changes how array methods called on tracked state return their elements, and adds a per-evaluation read cache plus a dev-mode warning for selectors that repeatedly read the same field in a loop. The stock Provider and useSelector are unchanged.
npm install react-redux@alpha
yarn add react-redux@alpha
pnpm add react-redux@alphaThis is still an alpha. Please try it out and give us feedback, especially on real apps using Reselect and entity adapters. The alpha.0 notes cover what useSignalSelector is and how to opt in.
After the alpha.0 release, we got feedback asking about two cases: reusing the same memoized selector instance across components, and conditional logic inside of a selector altering what fields it reads.
In alpha.0, every useSignalSelector evaluating against the same state object received the same tracking proxy. Reselect's argsMemoize (the weakMapMemoize default, and lruMemoize) keys its cache on argument identity, so the second evaluation with that proxy was a cache hit: the input selectors never ran, no state properties were read, and the hook recorded zero dependencies. That hook then never re-rendered.
This affected more than the reported case of two components sharing one createSelector. A single component with an inline wrapper (useSignalSelector(s => selectSummary(s).total)), a parametrized selector (selectScaled(s, factor)), nested memoized inputs, and components mounted after the cache was warm all went deaf after their first update.
Every tracked evaluation now gets a fresh root proxy. The consequence is that argsMemoize misses on every tracked run and the input selectors execute each time. The result function still memoizes on the input values, so derived objects keep stable identities and are shared across components as before. Hand-rolled caches that never read state (if (cached) return cached) still cannot be tracked, but those are equally stale under useSelector.
We also reviewed conditional selectors (s => s.toggle ? s.foo : s.bar). Turns out those already worked :) Dependencies are re-recorded from scratch on every evaluation, so switching branches drops the old branch and picks up the new one.
Once we fixed the cache bug and re-ran the benchmarks, we saw that the alpha.0 benchmark results were flawed. In particular, the derived-selectors benchmark had appeared to be a significant perf improvement over stock useSelector. However, with the cache fix in place, the correct behavior had more overhead. More hooks actually received updates, and result functions that iterated arrays of tracking proxies (selectAll, then .filter over the result) paid one proxy trap and one dependency registration per element read, per hook, per dispatch. Inside a Reselect result function that precision buys nothing, since the function re-runs on input identity anyway.
To address this, find, findLast, filter, slice, and now map return raw state objects instead of proxies, each with a single identity dependency on the element's path (items.{id:42} for arrays with a key field, items.3 otherwise). Because state is immutable, an identity dependency never misses a change to that element; it can only over-run when a field you did not read changes. Fields read off a returned element are not tracked separately. Direct index access (state.items[0].name) keeps field-level precision.
For map, callbacks that return the element itself, a primitive, or a proxy obtained elsewhere (ids.map(id => entities[id])) get precise dependencies. Callbacks that construct new objects fall back to one dependency on the whole array. forEach, reduce, and flatMap are still not overridden and depend on the whole array.
One side effect: elements returned from these methods compare correctly with === against references held outside the selector, without unwrap().
A selector like comments.filter(c => c.postId === post.id) reads post.id once per comment. When post is a tracking proxy, each read is a trap call. Within one evaluation that read is idempotent: the value cannot change and the dependency is already linked. Each proxy now remembers its last primitive read for the current evaluation and returns it directly on repeat.
In development, a selector that re-reads the same field 100+ times in a single evaluation logs a warning once, naming the path and suggesting hoisting the value into a local before the loop. Hoisting is still cheaper than the memo, but the memo recovers most of the difference without code changes.
Overall, the branch is still a significant perf win across most of our benchmark scenarios, and it now correctly handles additional common usage scenarios that we'd expect to see in real app code.
10 s per scenario, this release vs 9.3.0, Chrome, react-dom/profiling. "Script" is total scripting time; "blocked" is main-thread time inside dispatch().
| Scenario | Script | Blocked | Notes |
|---|---|---|---|
| tree-view | -55% | -76% | |
| entity-list-array | -49% | -85% | stock drops frames |
| many-components-many-slices | -37% | -56% | |
| deeptree-nested-hooks | -28% | -63% | |
| realistic-slice-count | -26% | -80% | |
| price-ticker | -21% | -59% | |
| forms | -20% | -81% | |
| multi-selector-component | -17% | -84% | |
| selective-update | -16% | -66% | |
| rapid-dispatch | -14% | -65% | |
| entity-list | +2% | -21% | noise |
| many-components-same-slice | +3% | +93% | flat; work moved into dispatch |
| rtkq-separate-queries | +9% | +25% | |
| one-component-many-slices | +19% | +22% | 20,000 top-level keys |
| derived-selectors | +36% | +119% | see below |
Render counts match 9.3.0 within noise on every scenario.
The alpha.0 notes reported derived-selectors at -87%. That number was wrong: 150 of the 200 hooks in that scenario were affected by the cache bug and never re-rendered after their first update. With the fix, every hook re-runs its input selectors through the tracking proxy on every relevant dispatch, and that is the cost shown.
one-component-many-slices improved from +36% in alpha.0 to +19%.
Bundle cost is unchanged from alpha.0: zero for apps that do not import useSignalSelector, about +7 kB min+gz for apps that do.
The useSignalSelector API page now covers array-method return values, the Reselect interaction, and the repeated-read behavior.
Full Changelog: v9.4.0-alpha.0...v9.4.0-alpha.1
This alpha release adds an opt-in useSignalSelector hook and SignalProvider component that only re-run selectors whose state dependencies actually cha
This alpha release adds an opt-in useSignalSelector hook and SignalProvider component that only re-run selectors whose state dependencies actually changed, plus a react-redux/signals entry point for adopting them app-wide, and restructures the hooks API docs into separate pages.
npm install react-redux@alpha
yarn add react-redux@alpha
pnpm add react-redux@alphaThis is an early alpha. The implementation is complete and heavily tested, but it has only been tried in a small number of real apps. Please try it out and give us feedback! We'd especially like to hear about performance differences after adopting useSignalSelector (render counts and dispatch timings), any differences or issues with selector behaviors (including edge cases in proxy wrapper access), and bundle sizes.
useSignalSelector and SignalProviderRedux is a simple event emitter, with O(n) subscriber behavior. Every dispatched action triggers a loop over all subscriber callbacks, which in turn normally call getState() and a selector to determine if that useSelector or connect needs to re-render. React-Redux moves some of the tracking to be internal to itself and optimizes some subscription aspects, but it's fundamentally still calling O(n) callbacks every time. An app with 2,000 mounted useSelector hooks runs 2,000 selector functions per dispatch, then compares 2,000 results, even when the action touched one field. That work is usually cheap per selector but it scales linearly with app size and is the dominant per-dispatch cost in large apps.
As with React, this works fine for most apps, but breaks down at large scales. I've talked with teams that had 20,000 connected components, and at that scale just running the callbacks themselves is a major perf issue.
Proxies allow tracking access to nested fields. Signals allow automatically deriving dependencies. More magic, but signals libs automatically only update the dependencies that actually rely on a given updated value.
We can't and won't change the semantics of Redux in terms of immutable updates, subscribing to the store, etc. But, we can leverage some of these techniques inside of React-Redux, invisibly to the end user.
useSignalSelector tracks which state paths each selector actually reads. Selectors run against a tracking proxy over the Redux state, which records property accesses like state.todos[3].text. On each dispatch, SignalProvider diffs the previous and next state trees and fires signals for the paths that changed. Only selectors that depend on a changed path re-run. Everything else is skipped entirely: no selector call, no equality check, no render.
You can adopt this incrementally. SignalProvider is a drop-in replacement for Provider, and useSignalSelector has the same signature and options as useSelector and passes the entire existing useSelector test suite, so you can switch individual components:
import { SignalProvider, useSignalSelector } from 'react-redux'
function TodoText({ id }: { id: number }) {
const text = useSignalSelector((state) => state.todos.byId[id].text)
return <span>{text}</span>
}Alternately, you can alias the whole app at once. The new react-redux/signals entry point exports SignalProvider as Provider and useSignalSelector as useSelector, so existing code and third-party libraries that import from react-redux pick up the new implementation without edits:
// vite.config.ts
export default defineConfig({
resolve: {
alias: { 'react-redux': 'react-redux/signals' },
},
})connect, useDispatch, useStore, and stock useSelector continue to work unchanged inside a SignalProvider. Reselect selectors work as expected, including weakMapMemoize. Zombie-child and stale-props behavior matches useSelector. SSR produces identical markup.
We benchmarked the branch against 9.3.0 across 16 scenarios in our react-redux-benchmarks suite, 10 seconds each, using React DevTools profiling builds so render counts are exact.
Total script time improved in 13 of 16 scenarios. Time spent inside dispatch() dropped 49–88% in 12 of 16. Render counts matched 9.3.0 within a few percent everywhere except the scenarios where 9.3.0 was dropping frames under load, where signals renders more often because it keeps up. Some representative numbers:
| Scenario | Script | Time in dispatch() |
Avg dispatch | Renders |
|---|---|---|---|---|
| derived-selectors | -87% | -70% | 1.47 → 0.44 ms | 347 → 30 |
| tree-view | -55% | -73% | 9.1 → 2.3 ms | ≈ |
| multi-selector-component | -28% | -88% | 6.5 → 0.9 ms | ≈ |
| realistic-slice-count | -28% | -82% | 1.15 → 0.21 ms | 768 → 768 |
| many-components-many-slices | -30% | -49% | 8.1 → 3.7 ms | ≈ |
| price-ticker | -19% | -58% | 24.3 → 6.2 ms | 247 → 410 |
| forms | -20% | -80% | 0.92 → 0.18 ms | ≈ |
The gains come from skipping work: in derived-selectors, 9.3.0 re-runs every derived selector on each dispatch and renders 347 times; signals renders 30 times, and the extra renders in 9.3.0 were all wasted.
There are costs. A tracked selector evaluation is 3–4x slower than a raw one because it runs through a proxy, so a selector that does re-run costs more than before. Each dispatch pays a diff of the previous and next state; this is proportional to how much of the tree actually changed, since unchanged subtrees are skipped by reference. Mount is a few milliseconds slower on small apps and faster on large component trees. The one scenario that regresses is a single component whose selector reads thousands of top-level state keys (+36% script), where there is no precision to recover and the diff is pure overhead.
The biggest tradeoff is bundle size. Opting in costs about 22.7 kB minified / 7.2 kB min+gzip more (32.9 kB / 10.9 kB total), which includes the alien-signals runtime. This is an intentional tradeoff - the extra logic and internal complexity requires more code. Stick with the standard useSelector as a default - useSignalSelector is specifically meant for larger apps that will have a net benefit from its performance characteristics.
The good news is that apps that keep using Provider and useSelector pay nothing for this feature. Stock React-Redux in a Vite 8 build is 10.2 kB minified / 3.7 kB min+gzip, unchanged from 9.3.0, and we have a CI check confirming the signals code tree-shakes out. Note that the raw dist/ files grew a lot because the signals code ships in the same file; bundle-size bots that measure dist/ will report a large increase that does not reflect what your app ships.
Path tracking works by observing property reads and diffing plain data. That imposes rules that stock useSelector does not:
useSelector tolerates violations that useSignalSelector does not. If a reducer mutates an object in place and returns the same reference, the diff sees no change and dependent components will not update. Map, Set, Date, and class instances are tracked by reference only: replacing one triggers updates, mutating one does not.state.items.sort(), delete state.x, Object.assign(state.y, ...)) throws a TypeError with a clear message. Stock useSelector silently allows this. Use slice().sort() or toSorted().useSignalSelector results are the same references stock useSelector would return and are safe to use as useEffect deps or Map keys. If you pass state objects out of the selector by some other route, unwrap() converts them back to raw state.useSignalSelector(state => state) never updates. Returning the root state (or otherwise reading nothing specific from it) gives the tracker nothing to depend on. Select the fields you need.state.todos.map(t => t.text) depends on the text column across all todos, not on every property of every todo. Mapping and then reading deeper properties works, but may re-run more often than the minimal set.Details for each are on the useSignalSelector and SignalProvider API pages.
The single "Hooks" API page has been split into separate pages for useSelector, useDispatch, and useStore, with the hooks overview page now serving as an index. New pages cover SignalProvider, useSignalSelector, and unwrap.
Full Changelog: v9.3.0...v9.4.0-alpha.0
This feature release officially marks the connect API as deprecated.
This feature release officially marks the connect API as deprecated.
That's it. That's the release. :)
connect deprecationWay back in 2022, I officially marked the original Redux core createStore method as deprecated in Redux 4.2.0. As I clearly stated in that release, the goal of marking createStore as deprecated was to encourage users to migrate to modern Redux Toolkit, especially for those users who don't read our docs (such as beginners following outdated tutorials or in bootcamps, etc). The change was visual-only - adding @deprecated just marks the import with a strikethrough in an IDE, and the docblock references the "use modern Redux Toolkit" docs page. No runtime errors, no behavior changes, just an indication that the function is considered obsolete and you shouldn't use it directly any more. I also exported a legacy_createStore alias - same function, no deprecation attribute.
It's 4 years later, and I'm finally doing the same thing for connect :)
Again, nothing about connect's behavior is changing, and we do not intend to remove the connect API. But it's 2026, and hooks are the correct way to use React and React-Redux today.
We do strongly encourage users to migrate from connect to the useSelector / useDispatch hooks in general. This should result in codebases that are easier to understand and ought to improve performance slightly due to the way updates are handled.
As with before, React-Redux now exports a legacy_connect alias that does not have the deprecation attribute applied.
We had set up trusted publishing for React-Redux a couple years ago and did some releases with that enabled, but at some point I did a follow-up release that still used the previous manual workflow, and that lost the trusted publishing provenance flag. We had recent issues requesting a new release with trusted publishing enabled again, so we've fixed that with this release.
connect as deprecated by @markerikson in #2269Full Changelog: v9.2.0...v9.3.0
This feature release updates the React peer dependency to work with React 19, and improves treeshakeability of our build artifacts.
This feature release updates the React peer dependency to work with React 19, and improves treeshakeability of our build artifacts.
React 19 was just released! We've updated our peer dep to accept React 19, and updated our runtime and type tests to check against both React 18 and 19.
Also see Redux Toolkit v2.5.0 for the same peer dep update.
We've done some nitty-gritty optimization work to ensure bundlers correctly treeshake unused parts of the bundle.
Full Changelog: v9.1.2...v9.2.0
Replace usage of deprecated JSX global namespace with React.JSX by @aryaemami59 in #2163
This bugfix release removes the no-longer-necessary peer dependency on react-native, and tweaks a few TS types for compat with the upcoming React 19 release.
We've always had an awkward peer dependency on both ReactDOM and React Native, because of the need to import the unstable_batchedUpdates API directly from each reconciler. That's part of what led to the sequence of 9.x patch releases to deal with RN compat.
As of 9.0.3, we dropped the batching imports completely, since React 18 now batches by default. That means we didn't even have any remaining imports from react-native.
Meanwhile, React 18.3 just came out, but so did React Native 0.74. RN 0.74 still requires React 18.2.
This caused NPM users to have installation failures when trying to use React-Redux:
We no longer need to list RN as a peer dep, and dropping that also fixes the NPM installation issues as well.
useRef usages to be called with an explicit argument of undefined. by @aryaemami59 in #2164JSX global namespace with React.JSX by @aryaemami59 in #2163Full Changelog: v9.1.1...v9.1.2
This bugfix release fixes an issue with connect and React Native caused by changes to our bundling setup in v9. Nested connect calls should work corre
This bugfix release fixes an issue with connect and React Native caused by changes to our bundling setup in v9. Nested connect calls should work correctly now.
Equals constraint into an intersection type. by @DanielRosenwasser in #2123useIsomorphicLayoutEffect usage in React Native environments by @aryaemami59 in #2156Full Changelog: v9.1.0...v9.1.1
This minor release adds a new syntax for pre-typing hooks.
This minor release adds a new syntax for pre-typing hooks.
.withTypesPreviously, the approach for "pre-typing" hooks with your app settings was a little varied. The result would look something like the below:
import type { TypedUseSelectorHook } from "react-redux"
import { useDispatch, useSelector, useStore } from "react-redux"
import type { AppDispatch, AppStore, RootState } from "./store"
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const useAppStore = useStore as () => AppStoreReact Redux v9.1.0 adds a new .withTypes method to each of these hooks, analogous to the .withTypes method found on Redux Toolkit's createAsyncThunk.
The setup now becomes:
import { useDispatch, useSelector, useStore } from "react-redux"
import type { AppDispatch, AppStore, RootState } from "./store"
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
export const useAppSelector = useSelector.withTypes<RootState>()
export const useAppStore = useStore.withTypes<AppStore>()hook.withTypes<RootState>() method by @aryaemami59 in #2114Full Changelog: v9.0.4...v9.1.0
This bugfix release updates the React Native peer dependency to be >= 0.69 , to better reflect the need for React 18 compat and (hopefully) resolve is
This bugfix release updates the React Native peer dependency to be >= 0.69, to better reflect the need for React 18 compat and (hopefully) resolve issues with the npm package manager throwing peer dep errors on install.
Full Changelog: v9.0.3...v9.0.4
We still export a batch method, but it's effectively a no-op that just immediately runs the given callback, and we've marked it as @deprecated .
This bugfix release drops the ReactDOM / React Native specific use of render batching, as React 18 now automatically batches, and updates the React types dependencies
React-Redux has long depended on React's unstable_batchedUpdates API to help batch renders queued by Redux updates. It also re-exported that method as a util named batch.
However, React 18 now auto-batches all queued renders in the same event loop tick, so unstable_batchedUpdates is effectively a no-op.
Using unstable_batchedUpdates has always been a pain point, because it's exported by the renderer package (ReactDOM or React Native), rather than the core react package. Our prior implementation relied on having separate batch.ts and batch.native.ts files in the codebase, and expecting React Native's bundler to find the right transpiled file at app build time. Now that we're pre-bundling artifacts in React-Redux v9, that approach has become a problem.
Given that React 18 already batches by default, there's no further need to continue using unstable_batchedUpdates internally, so we've removed our use of that and simplified the internals.
We still export a batch method, but it's effectively a no-op that just immediately runs the given callback, and we've marked it as @deprecated.
We've also updated the build artifacts and packaging, as there's no longer a need for an alternate-renderers entry point that omits batching, or a separate artifact that imports from "react-native".
batch by @markerikson in #2104@types/react-dom and lower @types/react to min needed by @markerikson in #2105Full Changelog: v9.0.2...v9.0.3
This bugfix release makes additional tweaks to the React Native artifact filename to help resolve import and bundling issues with RN projects.
This bugfix release makes additional tweaks to the React Native artifact filename to help resolve import and bundling issues with RN projects.
.mjs to .js by @aryaemami59 in #2102Full Changelog: v9.0.1...v9.0.2
This bugfix release updates the package to include a new react-redux.react-native.js bundle that specifically imports React Native, and consolidates a
This bugfix release updates the package to include a new react-redux.react-native.js bundle that specifically imports React Native, and consolidates all of the 'react' imports into one file to save on bundle size (and enable some tricky React Native import handling).
Full Changelog: v9.0.0...v9.0.1
This release has breaking changes .
This major release:
useSelectorThis 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!)
React-Redux is a separate, package, but we expect you'll be upgrading them together.
# React-Redux
npm install react-redux
yarn add react-redux
# RTK
npm install @reduxjs/toolkit
yarn add @reduxjs/toolkit
# Standalone Redux core
npm install redux
yarn add reduxReact-Redux 7.x and 8.x worked with all versions of React that had hooks (16.8+, 17.x, 18.x). However, React-Redux v8 used React 18's new useSyncExternalStore hook. In order to maintain backwards compatibility with older React versions, we used the use-sync-external-store "shim" package that provided an official userland implementation of the useSyncExternalStore hook when used with React 16 or 17. This meant that if you were using React 18, there were a few hundred extra bytes of shim code being imported even though it wasn't needed.
For React-Redux v9, we're switching so that React 18 is now required! This both simplifies the maintenance burden on our side (fewer versions of React to test against), and also lets us drop the extra bytes because we can import useSyncExternalStore directly.
React 18 has been out for a year and a half, and other libraries like React Query are also switching to require React 18 in their next major version. This seems like a reasonable time to make that switch.
Similarly, React-Redux now depends on Redux core v5 for updated TS types (but not runtime behavior). We strongly encourage all Redux users to be using Redux Toolkit, which already includes the Redux core. Redux Toolkit 2.0 comes with Redux core 5.0 built in.
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/react-redux.mjs. Most build tools should pick this up. There's also a CJS artifact, and a second copy of the ESM file named react-redux.legacy-esm.js to support Webpack 4 (which does not recognize the exports field in package.json). There's also two special-case artifacts: an "alternate renderers" artifact that should be used for any renderer other than ReactDOM or React Native (such as the ink React CLI renderer), and a React Server Components artifact that throws when any import is used (since using hooks or context would error anyway in an RSC environment). Additionally, all of the build artifacts now live under ./dist/ in the published package.
Previous releases actually shipped separate individual transpiled source files - the build artifacts are now pre-bundled, same as the rest of the Redux libraries.
We now publish modern JS syntax targeting ES2020, including optional chaining, object spread, and other modern syntax. If you need to . If you need to target older browsers, please transpile the packages yourself (or use the legacy-esm build artifact for ES2017).
We're now building the package using https://github.com/egoist/tsup. We also now include sourcemaps for the ESM and CJS artifacts.
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 react-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!
Per Mark's post "My Experience Modernizing Packages to ESM", one of the recent pain points has been the rollout of React Server Components and the limits the Next.js + React teams have added to RSCs. We see many users try to import and use React-Redux APIs in React Server Component files, then get confused why things aren't working right.
To address that, we've added a new entry point with a "react-server" condition. Every export in that file will throw an error as soon as it's called, to help catch this mistake earlier.
In v8.1.0, we updated useSelector to accept an options object containing options to check for selectors that always calculate new values, or that always return the root state.
We've renamed the noopCheck option to identityFunctionCheck for clarity. We've also changed the structure of the options object to be:
export type DevModeCheckFrequency = 'never' | 'once' | 'always'
export interface UseSelectorOptions<Selected = unknown> {
equalityFn?: EqualityFn<Selected>
devModeChecks?: {
stabilityCheck?: DevModeCheckFrequency
identityFunctionCheck?: DevModeCheckFrequency
}
}hoist-non-react-statics and react-is Deps InlinedHigher Order Components have been discouraged in the React ecosystem over the last few years. However, we still include the connect API. It's now in maintenance mode and not in active development.
As described in the React legacy docs on HOCs, one quirk of HOCs is needing to copy over static methods to the wrapper component. The hoist-non-react-statics package has been the standard tool to do that.
We've inlined a copy of hoist-non-react-statics and removed the package dep, and confirmed that this improves tree-shaking.
We've also done the same with the react-is package as well, which was also only used by connect.
This should have no user-facing effects.
We've dropped support for TS 4.6 and earlier, and our support matrix is now TS 4.7+.
uSES imports and run against RTK CI examples by @markerikson in #2070sideEffects: "false" to package.json in v9 by @markerikson in #2079react-is utils to fix tree-shaking in 9.0 by @markerikson in #2085noopCheck to identityFunctionCheck by @aryaemami59 in #2091Full Changelog: v8.1.2...v9.0.0
…for an overview of breaking changes in RTK 2.0 and Redux core.
This release candidate improves tree-shaking behavior in v9 to account for changes in bundling setup.
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 react-redux@next
yarn add react-redux@next
sideEffects: "false" to package.json in v9 by @markerikson in https://github.com/reduxjs/react-redux/pull/2079react-is utils to fix tree-shaking in 9.0 by @markerikson in https://github.com/reduxjs/react-redux/pull/2085Full Changelog: https://github.com/reduxjs/react-redux/compare/v9.0.0-beta.0...v9.0.0-rc.0
This beta release fixes the imports of use-sync-external-store when used in an ESM environment, and includes the fixes in v8.1.3.
This beta release fixes the imports of use-sync-external-store when used in an ESM environment, and includes the fixes in v8.1.3.
npm i react-redux@beta
yarn add react-redux@beta
We currently do not anticipate any major development or changes with React-Redux before v9 goes final, but that will be done in conjunction with the Redux Toolkit 2.0 release when it is ready.
uSES imports and run against RTK CI examples by @markerikson in https://github.com/reduxjs/react-redux/pull/2070Full Changelog: https://github.com/reduxjs/react-redux/compare/v9.0.0-alpha.1...v9.0.0-beta.0
This alpha release adds an extra entry point that will automatically throw errors when any API is used in a React Server Components environment, inlin
This alpha release adds an extra entry point that will automatically throw errors when any API is used in a React Server Components environment, inlines the hoist-non-react-statics dep, and updates context types.
Per Mark's post "My Experience Modernizing Packages to ESM", one of the recent pain points has been the rollout of React Server Components and the limits the Next.js + React teams have added to RSCs. We see many users try to import and use React-Redux APIs in React Server Component files, then get confused why things aren't working right.
To address that, we've added a new entry point with a "react-server" condition. Every export in that file will throw an error as soon as it's called, to help catch this mistake earlier.
hoist-non-react-statics Dep InlinedHigher Order Components have been discouraged in the React ecosystem over the last few years. However, we still include the connect API. It's now in maintenance mode and not in active development.
As described in the React legacy docs on HOCs, one quirk of HOCs is needing to copy over static methods to the wrapper component. The hoist-non-react-statics package has been the standard tool to do that.
We've inlined a copy of hoist-non-react-statics and removed the package dep, with the hope that this will ensure better tree-shaking in some projects.
We've made some tweaks to our ReactReduxContextValue type to better reflect actual behavior.
Full Changelog: https://github.com/reduxjs/react-redux/compare/v9.0.0-alpha.0...v9.0.0-alpha.1
This release has many changes to our build setup and published package contents, and has breaking changes.
This is an alpha release for React-Redux 9.0. This release has many changes to our build setup and published package contents, and has breaking changes.
npm i react-redux@alpha
yarn add react-redux@alpha
This is part of the next set of major versions for all of the Redux packages, including:
Please try out this alpha and give us feedback on how it works!
React-Redux 7.x and 8.x worked with all versions of React that had hooks (16.8+, 17.x, 18.x). However, React-Redux v8 used React 18's new useSyncExternalStore hook. In order to maintain backwards compatibility with older React versions, we used the use-sync-external-store "shim" package that provided an official userland implementation of the useSyncExternalStore hook when used with React 16 or 17. This meant that if you were using React 18, there were a few hundred extra bytes of shim code being imported even though it wasn't needed.
For React-Redux v9, we're switching so that React 18 is now required! This both simplifies the maintenance burden on our side (fewer versions of React to test against), and also lets us drop the extra bytes because we can import useSyncExternalStore directly.
React 18 has been out for a year and a half, and other libraries like React Query are also switching to require React 18 in their next major version. This seems like a reasonable time to make that switch.
Similarly, React-Redux now depends on Redux core v5 for updated TS types (but not runtime behavior).
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. We've now applied those same packaging changes to React-Redux.
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're also using the CLI from 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/react-redux.mjs. Most build tools should pick this up. There's also a CJS artifact, and a second copy of the ESM file named react-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.
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.
The Redux packages have 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/react-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!
For this initial alpha, we've marked the React-Redux bundles with the "use client" label. This at least seems to let an example Next.js app build even if it imports useSelector into an RSC page file, but to be honest we're still figuring this stuff out! Expect further changes before a final release.
React-Redux now depends on the updated TS types from Redux core v5. This mostly involves uses of UnknownAction everywhere instead of AnyAction.
Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.1.2...v9.0.0-alpha.0
This bugfix release fixes an issue with subscriptions being lost when lazy-loaded components are used with React Suspense, and includes stack traces i
This bugfix release fixes an issue with subscriptions being lost when lazy-loaded components are used with React Suspense, and includes stack traces in useSelector usage warnings .
Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.1.2...v8.1.3
This version changes imports from the React package to namespace imports so the package can safely be imported in React Server Components as long as y
This version changes imports from the React package to namespace imports so the package can safely be imported in React Server Components as long as you don't actually use it - this is for example important if you want to use the React-specifc createApi function from Redux Toolkit.
Some other changes:
globalThis (in this case it will fall back to the previous behaviour).Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.1.1...v8.1.2
This bugfix release tweaks the recent lazy context setup logic to ensure a single React context instance per React version, and removes the recently a
This bugfix release tweaks the recent lazy context setup logic to ensure a single React context instance per React version, and removes the recently added RTK peerdep to fix an issue with Yarn workspaces.
React Context has always relied on reference identity. If you have two different copies of React or a library in a page, that can cause multiple versions of a context instance to be created, leading to problems like the infamous "Could not find react-redux context" error.
In v8.1.0, we reworked the internals to lazily create our single ReactReduxContext instance to avoid issues in a React Server Components environment.
This release further tweaks that to stash a single context instance per React version found in the page, thus hopefully avoiding the "multiple copies of the same context" error in the future.
Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.1.0...v8.1.1
This feature release adds new development-mode safety checks for common errors (like poorly-written selectors), adds a workaround to fix crash errors
This feature release adds new development-mode safety checks for common errors (like poorly-written selectors), adds a workaround to fix crash errors when React-Redux hooks are imported into React Server Component files, and updates our hooks API docs page with improved explanations and updated links.
useSelectorWe've had a number of users tell us over time that it's common to accidentally write selectors that have bad behavior and cause performance issues. The most common causes of this are either selectors that unconditionally return a new reference (such as state => state.todos.map() without any memoization ), or selectors that actually return the entire root state ( state => state ).
We've updated useSelector to add safety checks in development mode that warn if these incorrect behaviors are detected:
useSelector will warn if the results are different referencesuseSelector will warn if the selector result is actually the entire root stateBy default, these checks only run once the first time useSelector is called. This should provide a good balance between detecting possible issues, and keeping development mode execution performant without adding many unnecessary extra selector calls.
If you want, you can configure this behavior globally by passing the enum flags directly to <Provider>, or on a per-useSelector basis by passing an options object as the second argument:
// Example: globally configure the root state "noop" check to run every time
<Provider store={store} noopCheck="always">
{children}
</Provider>
// Example: configure `useSelector` to specifically run the reference checks differently:
function Component() {
// Disable check entirely for this selector
const count = useSelector(selectCount, { stabilityCheck: 'never' })
// run once (default)
const user = useSelector(selectUser, { stabilityCheck: 'once' })
// ...
}
This goes along with the similar safety checks we've added to Reselect v5 alpha as well.
We're still trying to work out how to properly use Redux and React Server Components together. One possibility is using RTK Query's createApi to define data fetching endpoints, and using the generated thunks to fetch data in RSCs, but it's still an open question.
However, users have reported that merely importing any React-Redux API in an RSC file causes a crash, because React.createContext is not defined in RSC files. RTKQ's React-specific createApi entry point imports React-Redux, so it's been unusable in RSCs.
This release adds a workaround to fix that issue, by using a proxy wrapper around our singleton ReactReduxContext instance and lazily creating that instance on demand. In testing, this appears to both continue to work in all unit tests, and fixes the import error in an RSC environment. We'd appreciate further feedback in case this change does cause any issues for anyone!
We've also tweaked the internals of the hooks to do checks for correct <Provider> usage when using a custom context, same as the default context checks.
We've cleaned up some of the Hooks API reference page, and updated links to the React docs.
Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.7...v8.1.0
This release updates the peer dependencies to accept Redux Toolkit, and accept the ongoing RTK and Redux core betas as valid peer deps.
This release updates the peer dependencies to accept Redux Toolkit, and accept the ongoing RTK and Redux core betas as valid peer deps.
Note: These changes were initially in 8.0.6, but that had a typo in the peer deps that broke installation. Sorry!
Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.5...v8.0.7
~~This release updates the peer dependencies to accept Redux Toolkit, and accept the ongoing RTK and Redux core betas as valid peer deps.~~
This release updates the peer dependencies to accept Redux Toolkit, and accept the ongoing RTK and Redux core betas as valid peer deps.
This release has a peer deps typo that breaks installation - please use 8.0.7 instead !
Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.5...v8.0.6
This release fixes a few minor TS issues.
This release fixes a few minor TS issues.
Provider: pass state (S) generic through to ProviderProps by @OliverJAsh in https://github.com/reduxjs/react-redux/pull/1960equalityFn type in NoInfer by @phryneas in https://github.com/reduxjs/react-redux/pull/1965Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.4...v8.0.5
This patch release fixes some minor TS types issues, and updates the rarely-used areStatesEqual option for connect to now pass through ownProps for ad
This patch release fixes some minor TS types issues, and updates the rarely-used areStatesEqual option for connect to now pass through ownProps for additional use in determining which pieces of state to compare if desired.
Note: 8.0.3 was accidentally published without one of these fixes. Use 8.0.4 instead.
We've fixed an import of React that caused issues with the allowSyntheticDefaultImports TS compiler flag in user projects.
connect already accepted a custom context instance as props.context, and had runtime checks in case users were passing through a real value with app data as props.context instead. However, the TS types did not handle that case, and this would fail to compile. If your own component expects props.context with actual data, connect's types now use that type instead.
The ConnectedProps<T> type had a mismatch with React's built-in React.ComponentProps<Component> type, and that should now work correctly.
The areStatesEqual option to connect now receives ownProps as well, in case you need to make a more specific comparison with certain sections of state.
The new signature is:
{
areStatesEqual?: (
nextState: State,
prevState: State,
nextOwnProps: TOwnProps,
prevOwnProps: TOwnProps
) => boolean
}
ComponentProps from older @types/react by @Andarist in https://github.com/reduxjs/react-redux/pull/1956Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.2...v8.0.4
This release was accidentally published without an intended fix - please use [v8.0.4](https://github.com/reduxjs/react-redux/releases/tag/v8.0.4) inst
This release was accidentally published without an intended fix - please use v8.0.4 instead
This patch release tweaks the behavior of connect to print a one-time warning when the obsolete pure option is passed in, rather than throwing an erro
This patch release tweaks the behavior of connect to print a one-time warning when the obsolete pure option is passed in, rather than throwing an error. This fixes crashes caused by libraries such as react-beautiful-dnd continuing to pass in that option (unnecessarily) to React-Redux v8.
Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.1...v8.0.2
This release fixes an incorrect internal import of our Subscription type, which was causing TS compilation errors in some user projects. We've also li
This release fixes an incorrect internal import of our Subscription type, which was causing TS compilation errors in some user projects. We've also listed @types/react-dom as an optional peerDep. There are no runtime changes in this release.
Subscription causes noImplicitAny error by @vicrep in https://github.com/reduxjs/react-redux/pull/1910Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.0...v8.0.1
…modernizes build output, and removes the deprecated connectAdvanced API and the pure option for connect.
This major version release updates useSelector, connect, and <Provider> for compatibility with React 18, rewrites the React-Redux codebase to TypeScript (obsoleting use of @types/react-redux), modernizes build output, and removes the deprecated connectAdvanced API and the pure option for connect.
npm i react-redux@latest
yarn add react-redux@latest
Our public API is still the same ( <Provider>, connect and useSelector/useDispatch), but we've updated the internals to use the new useSyncExternalStore hook from React. React-Redux v8 is still compatible with all versions of React that have hooks (16.8+, 17.x, and 18.x; React Native 0.59+), and should just work out of the box.
In most cases, it's very likely that the only change you will need to make is bumping the package version to "react-redux": "^8.0".
If you are using the rarely-used connectAdvanced API, you will need to rewrite your code to avoid that, likely by using the hooks API instead. Similarly, the pure option for connect has been removed.
If you are using Typescript, React-Redux is now written in TS and includes its own types. You should remove any dependencies on @types/react-redux.
While not directly tied to React-Redux, note that the recently updated @types/react@18 major version has changed component definitions to remove having children as a prop by default. This causes errors if you have multiple copies of @types/react in your project. To fix this, tell your package manager to resolve @types/react to a single version. Details:
React issue #24304: React 18 types broken since release
Additionally, please see the React post on How to Ugprade to React 18 for details on how to migrate existing apps to correctly use React 18 and take advantage of its new features.
React-Redux now requires the new useSyncExternalStore API in React 18. By default, it uses the "shim" package which backfills that API in earlier React versions, so React-Redux v8 is compatible with all React versions that have hooks (16.8+, and React Native 0.59+) as its acceptable peer dependencies.
We'd especially like to thank the React team for their extensive support and cooperation during the useSyncExternalStore development effort. They specifically designed useSyncExternalStore to support the needs and use cases of React-Redux, and we used React-Redux v8 as a testbed for how useSyncExternalStore would behave and what it needed to cover. This in turn helped ensure that useSyncExternalStore would be useful and work correctly for other libraries in the ecosystem as well.
Our performance benchmarks show parity with React-Redux v7.2.5 for both connect and useSelector, so we do not anticipate any meaningful performance regressions.
useSyncExternalStore and BundlingThe useSyncExternalStore shim is imported directly in the main entry point, so it's always included in bundles even if you're using React 18. This adds roughly 600 bytes minified to your bundle size.
If you are using React 18 and would like to avoid that extra bundle cost, React-Redux now has a new /next entry point. This exports the exact same APIs, but directly imports useSyncExternalStore from React itself, and thus avoids including the shim. You can alias "react-redux": "react-redux/next" in your bundler to use that instead.
React 18 introduces a new hydrateRoot method for hydrating the UI on the client in Server-Side Rendering usage. As part of that, the useSyncExternalStore API requires that we pass in an alternate state value other than what's in the actual Redux store, and that alternate value will be used for the entire initial hydration render to ensure the initial rehydrated UI is an exact match for what was rendered on the server. After the hydration render is complete, React will then apply any additional changes from the store state in a follow-up render.
React-Redux v8 supports this by adding a new serverState prop for <Provider>. If you're using SSR, you should pass your serialized state to <Provider> to ensure there are no hydration mismatch errors:
import { hydrateRoot } from 'react-dom/client'
import { configureStore } from '@reduxjs/toolkit'
import { Provider } from 'react-redux'
const preloadedState = window.__PRELOADED_STATE__
const clientStore = configureStore({
reducer: rootReducer,
preloadedState,
})
hydrateRoot(
document.getElementById('root'),
<Provider store={clientStore} serverState={preloadedState}>
<App />
</Provider>
)
The React-Redux library source has always been written in plain JS, and the community maintained the TS typings separately as @types/react-redux.
We've (finally!) migrated the React-Redux codebase to TypeScript, using the existing typings as a starting point. This means that the @types/react-redux package is no longer needed, and you should remove that as a dependency.
Note Please ensure that any installed copies of
reduxand@types/reactare de-duped. You are also encouraged to update to the latest versions of Redux Toolkit (1.8.1+) or Redux (4.1.2), to ensure consistency between installed types and avoid problems from types mismatches.
We've tried to maintain the same external type signatures as much as possible. If you do see any compile problems, please file issues with any apparent TS-related problems so we can review them.
The TS migration was a great collaborative effort, with many community members contributing migrated files. Thank you to everyone who helped out!
In addition to the "pre-typed" TypedUseSelectorHook, there's now also a Connect<State = unknown> type that can be used as a "pre-typed" version of connect as well.
As part of the process, we also updated the repo to use Yarn 3, copied the typetests files from DefinitelyTyped and expanded them, and improved our CI setup to test against multiple TS versions.
DefaultRootState typeThe @types/react-redux package, which has always been maintained by the community, included a DefaultRootState interface that was intended for use with TS's "module augmentation" capability. Both connect and useSelector used this as a fallback if no state generic was provided. When we migrated React-Redux to TS, we copied over all of the types from that package as a starting point.
However, the Redux team specifically considers use of a globally augmented state type to be an anti-pattern. Instead, we direct users to extract the RootState and AppDispatch types from the store setup, and create pre-typed versions of the React-Redux hooks for use in the app.
Now that React-Redux itself is written in TS, we've opted to remove the DefaultRootState type entirely. State generics now default to unknown instead.
Technically the module augmentation approach can still be done in userland, but we discourage this practice.
We've always targeted ES5 syntax in our published build artifacts as the lowest common denominator. Even the "ES module" artifacts with import/export keywords still were compiled to ES5 syntax otherwise.
With IE11 now effectively dead and many sites no longer supporting it, we've updated our build tooling to target a more modern syntax equivalent to ES2017, which shrinks the bundle size slightly.
If you still need to support ES5-only environments, please compile your own dependencies as needed for your target environment.
We announced in 2019 that the legacy connectAdvanced API would be removed in the next major version, as it was rarely used, added internal complexity, and was also basically irrelevant with the introduction of hooks. As promised, we've removed that API.
We've also removed the pure option for connect, which forced components to re-render regardless of whether props/state had actually changed if it was set to false. This option was needed in some cases in the early days of the React ecosystem, when components sometimes relied on external mutable data sources that could change outside of rendering. Today, no one writes components that way, the option was barely used, and React 18's useSyncExternalStore strictly requires immutable updates. So, we've removed the pure flag.
Given that both of these options were almost never used, this shouldn't meaningfully affect anyone.
Due to the TS migration effort and number of contributors, this list covers just the major changes:
pure removal by @Andarist in https://github.com/reduxjs/react-redux/pull/1859useSyncExternalStore shim behavior and update React deps by @markerikson in https://github.com/reduxjs/react-redux/pull/1884DefaultRootState type by @markerikson in https://github.com/reduxjs/react-redux/pull/1887serverState behavior by @markerikson in https://github.com/reduxjs/react-redux/pull/1888peerDependencies by @kyletsang in https://github.com/reduxjs/react-redux/pull/1893dispatchProp arg in mergeProps by @markerikson in https://github.com/reduxjs/react-redux/pull/1897https://github.com/reduxjs/react-redux/compare/v7.2.4...v8.0.0
This release candidate updates our peer deps to accept all React versions with hooks (16.8+, 17+, and 18+), as well as React Native (0.59+). (The code
This release candidate updates our peer deps to accept all React versions with hooks (16.8+, 17+, and 18+), as well as React Native (0.59+). (The code already worked, but the peer deps needed to be updated to match behavior and install correctly.)
At this point, React-Redux v8 is feature-complete and stable. We still really want users to try this out and give us feedback before the final release! Barring any reported issues, we plan to release 8.0 as final within the next few days.
peerDependencies by @kyletsang in https://github.com/reduxjs/react-redux/pull/1893Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.0-rc.0...v8.0.0-rc.1
This release candidate removes the DefaultRootState type left over from the @types/react-redux package. Additionally, we now have tests that exercise
This release candidate removes the DefaultRootState type left over from the @types/react-redux package. Additionally, we now have tests that exercise the serverState SSR behavior added in a previous beta.
At this point, React-Redux v8 is feature-complete and stable. We still really want users to try this out and give us feedback before the final release! Barring any reported issues, we plan to release 8.0 as final within the next few days.
DefaultRootState typeThe @types/react-redux package, which has always been maintained by the community, included a DefaultRootState interface that was intended for use with TS's "module augmentation" capability. Both connect and useSelector used this as a fallback if no state generic was provided. When we migrated React-Redux to TS, we copied over all of the types from that package as a starting point.
However, the Redux team specifically considers use of a globally augmented state type to be an anti-pattern. Instead, we direct users to extract the RootState and AppDispatch types from the store setup, and create pre-typed versions of the React-Redux hooks for use in the app.
Now that React-Redux itself is written in TS, we've opted to remove the DefaultRootState type entirely. State generics now default to unknown instead.
Technically the module augmentation approach can still be done in userland, but we discourage this practice.
We added a serverState prop to <Provider> in beta.2 to resolve hydration mismatch issues, but had only done some quick hands-on testing locally. We now have tests that cover that use case.
DefaultRootState type by @markerikson in https://github.com/reduxjs/react-redux/pull/1887serverState behavior by @markerikson in https://github.com/reduxjs/react-redux/pull/1888Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.0-beta.4...v8.0.0-rc.0
This beta release switches the default entry point to use the useSyncExternalStore shim for compatibility with React 16.8+, and switches to a "/next"
This beta release switches the default entry point to use the useSyncExternalStore shim for compatibility with React 16.8+, and switches to a "/next" alternate entry point without the shim.
At this point, React-Redux v8 is feature-complete and stable. We still really want users to try this out and give us feedback before the final release! We'd also like to add some additional tests around SSR behavior.
We would like to release v8 as final within the next couple weeks now that React 18 is available.
useSyncExternalStore Shim UsageReact 18 adds the new useSyncExternalStore API. In previous betas, the plan was that React-Redux v8 would have a hard requirement on React 18. As a fallback, the betas provided a "/compat" entry point that included the uSES "shim", a userland implementation from the React team that provided compatibility with earlier React versions back to 16.8. That adds a few hundred bytes to the bundle size, so we wanted to keep the default size smaller.
However, React Native will not support React 18 until the "New Architecture" is done. So, release React-Redux v8 with a hard React 18 requirement would immediately start breaking RN usage.
After discussion with the React team, we've flipped the default behavior in v8. Now, the default entry point does rely on the uSES shim. This increases final bundle size slightly (about 600b minified compared to v7.x). However, this ensures that React-Redux v8 is compatible with React 16.8+/17 out of the box, enabling users to upgrade to v8 right away even if they aren't using React 18. It also ensures continued RN compatibility.
For users who would like to strip out the shim, this release switches to having a "/next" entry point that directly imports useSyncExternalStore from React, with no shim. You can alias "react-redux": "react-redux/next" in your bundler to use that instead.
useSyncExternalStore shim behavior and update React deps by @markerikson in https://github.com/reduxjs/react-redux/pull/1884Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.0-beta.3...v8.0.0-beta.4
This beta release fixes a regression with unsubscribe performance in useSelector, and does some minor internal cleanup in connect.
This beta release fixes a regression with unsubscribe performance in useSelector, and does some minor internal cleanup in connect.
At this point, React-Redux v8 is likely feature-complete and stable. We still really want users to try this out and give us feedback before the final release! We'd also like to add some additional tests around SSR behavior.
The tentative plan is to do a final review of the code and behavior after React 18 goes final, then release React-Redux v8 final shortly after that.
useSelector Unsubscribe PerformanceIn 2019, we fixed a a reported issue with useSelector unsubscriptions showing quadratic performance, due to use of a single listeners array in our Subscription class. The fix was to switch to using a linked list to track subscribers.
When we reworked useSelector to use useSyncExternalStore for v8, we passed store.subscribe directly and stopped subscribing via a Subscription instance, thinking that we might no longer need Subscription any more. However, Subscription is still used by <Provider>, so it won't be removed from the bundle anyway, and the switch to using store.subscribe regressed the unsubscription performance because it does still use a listeners array as well.
We've switched back to having useSelector subscribe to the Subscription instance from <Provider>, and verified that this re-resolves the unsubscription performance behavior. We've also added a perf test to ensure that we capture this intended behavior and don't accidentally regress on this again in the future.
We've removed a couple additional references to the removed pure option in connect, and tweaked some of the types to remove a legacy signature for Provider that is no longer relevant.
pure removal by @Andarist in https://github.com/reduxjs/react-redux/pull/1859Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.0-beta.2...v8.0.0-beta.3
This beta release makes several fixes to the TypeScript types for v8, fixes several dev dependencies that were accidentally listed as dependencies, an
This beta release makes several fixes to the TypeScript types for v8, fixes several dev dependencies that were accidentally listed as dependencies, and adds initial React 18 SSR support.
The initial TS conversion effort ported a chunk of the typetests from the React-Redux v7 types in DefinitelyTyped. We've ported over the remainder of the typetests, which uncovered a few bugs and missing types (such as the useStore hook not being generic).
Those issues are now fixed, and after some additional tweaks all of the typetests are now passing. This means that existing TS usage of React-Redux v7 should be able to work entirely as-is with v8.
The new React 18 useSyncExternalStore hook accepts a function to supply the current state when called, which is normally the Redux store.getState method. However, a mutable store like Redux could change before or during an initial hydration render (such as a manual store.dispatch() before calling hydrateRoot(), or React components dispatching actions during the mount process). To avoid that, useSyncExternalStore also requires that you provide a getServerSnapshot function that can return a consistent single state value. uSES will use that all the way through the initial hydration render, and then check to see if any further updates are needed based on the latest state after the hydration render is complete.
The Provider component now accepts an optional serverState prop. If you're doing SSR, serialize your Redux store state on the server and pass that in to Provider as <Provider store={store} serverState={window.initialServerState}>, similar to how you would initialize a Redux store with that value.
We've updated both useSelector and connect to use the serverState value if it exists and pass that to useSyncExternalStore. This has been only briefly tested so far, but it appears to correctly eliminate hydration mismatch warnings.
We would really like more users to try this out and give us feedback!
Huge thanks to @Ephem for providing an SSR example to work with, and @acdlite for the API idea.
React-Redux now expects React 18 RC as a peer dep.
Several test libraries were accidentally added as dependencies in the previous betas, so they would get installed in user projects as well. Those have been moved back to devDependencies as intended.
Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.0-beta.1...v8.0.0-beta.2
This beta bugfix release fixes incorrect initialization of the useSyncExternalStore hook from beta.0 that caused it to crash on startup. Sorry!
This beta bugfix release fixes incorrect initialization of the useSyncExternalStore hook from beta.0 that caused it to crash on startup. Sorry!
npm i react-redux@next
yarn add react-redux@next
https://github.com/reduxjs/react-redux/compare/v8.0.0-beta.0...v8.0.0-beta.1
This beta release adds a new 'react-redux/compat' entry point for use with React 16.9+ 17.x, re-enabling broader compatibility across React versions t
This beta release adds a new 'react-redux/compat' entry point for use with React 16.9+ 17.x, re-enabling broader compatibility across React versions to make it easier to upgrade to React-Redux v8.
While there are no other changes since the previous alphas (and there's really been very minimal feedback reported on the alphas thus far), we believe the v8 pre-releases are stable enough to begin seriously evaluating them as upgrades in your apps. This also aligns with React 18 being upgraded to beta status and the useSyncExternalStore API stabilizing.
We would really appreciate users trying out this release with all compatible versions of React and reporting the results, even if it's just "yup, tried it and it works"! Please provide feedback in the linked discussion thread.
Overall, v8.0's major changes include:
@types/react-redux)useSyncExternalStore API for React 18 compatconnectAdvanced, the pure option for connect)For more details on those, see the v8.0.0-alpha.0 release notes.
Note: this release has a crash bug that is fixed in v8.0.0-beta.1 - please be sure to install the next tag or beta.1 specifically
npm i react-redux@next
yarn add react-redux@next
In 8.0.0-alpha.0, we switched the internals of connect and useSelector to use the new useSyncExternalStore API from React. At the time, that was only available in the form of a "shim" package that worked with multiple React versions.
In 8.0.0-alpha.1, useSyncExternalStore had been added to React itself. The original plan was always to make React-Redux v8 have a hard dependency on React 18, and the shim adds about 750 bytes to bundle size, so we dropped use of the shim entirely.
After suggestions from the community, we've now added a new 'react-redux/compat' entry point that falls back to using the shim. This should enable React-Redux v8 to work correctly with earlier versions of React that support hooks (16.9+ and 17.x), as well as Preact (which does not appear to be implementing useSyncExternalStore at this time).
We've updated our test suite to run all tests against both React 18 and the standard entry point with no uSES shim, and React 17 and the "compat" entry point with the uSES shim, and all tests are passing.
The likely approach for using this would be to alias or override your build setup to redirect imports of 'react-redux' to the 'react-redux/compat' entry point instead.
https://github.com/reduxjs/react-redux/compare/v8.0.0-alpha.1...v8.0.0-beta.0
This alpha preview release updates our React dependencies to the latest React 18 alpha versions, updates the internal usages of useSyncExternalStore t
This alpha preview release updates our React dependencies to the latest React 18 alpha versions, updates the internal usages of useSyncExternalStore to match those alpha changes, and changes the peerDependencies to specifically require React 18 alpha or beta versions.
npm i react-redux@next
yarn add react-redux@next
Since the previous React-Redux alpha, several more React 18 alpha versions have been released, some with meaningful changes. The useSyncExternalStore API has been promoted from the React "experimental" builds to the "alpha" channel, and the shim package's exports layout has been changed.
This release updates our internals to specifically import useSyncExternalStore from React itself. This means that starting with this release, React-Redux v8 requires a recent React 18 alpha/beta release that contains that API!
We'd appreciate folks trying this out with recent React builds and giving us feedback in the related issue:
Investigation: try out React-Redux v7 / v8 with React 18 alpha
Full Changelog: https://github.com/reduxjs/react-redux/compare/v8.0.0-alpha.0...v8.0.0-alpha.1
…modernizes build output, and removes the deprecated connectAdvanced API and the pure option for connect.
This is the initial alpha preview release for React-Redux v8.
This alpha release reworks useSelector and connect for compatibility with React 18, rewrites the React-Redux codebase to TypeScript (obsoleting use of @types/react-redux), modernizes build output, and removes the deprecated connectAdvanced API and the pure option for connect.
npm i react-redux@next
yarn add react-redux@next
This alpha release is intended for initial compatibility testing with React 18 and TypeScript. For general discussion of this release, see the associated thread in the Discussions section.
Our public API is still the same ( connect and useSelector/useDispatch), all of our tests pass, and apps should run okay. It's very possible that the only migration needed is to bump the package version.
However, it's likely that there will be types breakage due to the TypeScript migration, and runtime bugs are also possible due to the amount of internal refactoring and changes.
React-Redux now requires the new experimental useSyncExternalStore API in React 18. This release is using the "shim" package which backfills that API in earlier React versions, and currently lists 'react': '^16 || ^17 || 18' as its acceptable peer dependencies, so in theory it could run with React 16 and 17. However, we're planning to remove use of the shim and have a hard dependency on React 18 by the time version 8.0 goes final, so you are enouraged to try out this build with an "experimental" build of React 18 that contains useSyncExternalStore, such as version 0.0.0-experimental-7d38e4fd8-20210930, and follow the React 18 upgrade instructions.
React 18 will be introducing new APIs related to SSR and hydration, and React-Redux will likely need further updates to support those. This release stubs out the getServerSnapshot argument to useSyncExternalStore - we'll tackle this in a future alpha release.
The React-Redux library source has always been written in plain JS, and the community maintained the TS typings separately as @types/react-redux.
We've (finally!) migrated the React-Redux codebase to TypeScript, using the existing typings as a starting point. We've tried to maintain the same external type signatures as much as possible, but there will most likely be some compile breakages from the changes, and we may have missed some bits along the way. Please file issues with any apparent TS-related problems so we can review them.
The TS migration was a great collaborative effort, with many community members contributing migrated files. Thank you to everyone who helped out!
As part of the process, we also updated the repo to use Yarn 2, copied the typetests files from DefinitelyTyped and expanded them, and improved our CI setup to test against multiple TS versions.
Note When testing this out, you should remove the
@types/react-reduxpackage and ensure that any installed copies ofreduxare de-duped. You are also encouraged to update to the latest versions of Redux Toolkit (1.6.1+) or Redux (4.1.1), to ensure consistency between installed types and avoid problems from types mismatches.
Per the React 18 announcement overview, React 18 will include new capabilities like automatic render batching and opt-in support for "concurrent rendering". In order for external state libraries like Redux to take advantage of those, we need to use the new useSyncExternalStore API to let React better coordinate renders caused by external updates.
We've reworked both connect and useSelector to call useSyncExternalStore internally. This process is purely internal refactoring, and should require no changes to your own code.
Early performance benchmarks show parity with React-Redux v7.2.5 for both connect and useSelector, so we do not anticipate any meaningful performance regressions.
We've always targeted ES5 syntax in our published build artifacts as the lowest common denominator. Even the "ES module" artifacts with import/export keywords still were compiled to ES5 syntax otherwise.
With IE11 now effectively dead and many sites no longer supporting it, we've updated our build tooling to target a more modern syntax equivalent to ES2017, which shrinks the bundle size slightly.
If you still need to support ES5-only environments, please compile your own dependencies as needed for your target environment.
We announced in 2019 that the legacy connectAdvanced API would be removed in the next major version, as it was rarely used, added internal complexity, and was also basically irrelevant with the introduction of hooks. As promised, we've removed that API.
We've also removed the pure option for connect, which forced components to re-render regardless of whether props/state had actually changed if it was set to false. This option was needed in some cases in the early days of the React ecosystem, when components sometimes relied on external mutable data sources that could change outside of rendering. Today, no one writes components that way, the option was barely used, and React 18's useSyncExternalStore strictly requires immutable updates. So, we've removed the pure flag.
Given that both of these options were almost never used, this shouldn't meaningfully affect anyone.
Due to the TS migration effort and number of contributors, this list covers just the major changes:
https://github.com/reduxjs/react-redux/compare/v7.2.4...v8.0.0-alpha.0
This patch release updates the rarely-used areStatesEqual option for connect to now pass through ownProps for additional use in determining which piec
This patch release updates the rarely-used areStatesEqual option for connect to now pass through ownProps for additional use in determining which pieces of state to compare if desired.
The new signature is:
{
areStatesEqual?: (
nextState: State,
prevState: State,
nextOwnProps: TOwnProps,
prevOwnProps: TOwnProps
) => boolean
}
Full Changelog: https://github.com/reduxjs/react-redux/compare/v7.2.8...v7.2.9
This release fixes a bug in the 7.x branch that caused to unsubscribe and stop updating completely when used inside of React 18's . The new "strict ef
This release fixes a bug in the 7.x branch that caused <Provider> to unsubscribe and stop updating completely when used inside of React 18's <StrictMode>. The new "strict effects" behavior double-mounts components, and the subscription needed to be set up inside of a useLayoutEffect instead of a useMemo. This was previously fixed as part of v8 development, and we've backported it.
Note: If you are now using React 18, we strongly recommend using the React-Redux v8 beta instead of v7.x!. v8 has been rewritten internally to work correctly with React 18's Concurrent Rendering capabilities. React-Redux v7 will run and generally work okay with existing code, but may have rendering issues if you start using Concurrent Rendering capabilities in your code.
Now that React 18 is out, we plan to finalize React-Redux v8 and release it live within the next couple weeks. Per an update yesterday in the "v8 roadmap" thread, React-Redux v8 will be updated in the next couple days to ensure support for React 16.8+ as part of the next beta release. We would really appreciate final feedback on using React-Redux v8 beta with React 18 before we publish the final version.
Full Changelog: https://github.com/reduxjs/react-redux/compare/v7.2.7...v7.2.8
This release updates React-Redux v7's peer dependencies to accept React 18 as a valid version, _only_ to avoid installation errors caused by NPM's "in
This release updates React-Redux v7's peer dependencies to accept React 18 as a valid version, only to avoid installation errors caused by NPM's "install all the peer deps and error if they don't match" behavior.
Note: If you are now using React 18, we strongly recommend using the React-Redux v8 beta instead of v7.x!. v8 has been rewritten internally to work correctly with React 18's Concurrent Rendering capabilities. React-Redux v7 will run and generally work okay with existing code, but may have rendering issues if you start using Concurrent Rendering capabilities in your code.
Now that React 18 is out, we plan to finalize React-Redux v8 and release it live within the next couple weeks. We would really appreciate final feedback on using React-Redux v8 beta with React 18 before we publish the final version.
Just a quick fix for a Yarn install warning. Sorry about the noise!
Just a quick fix for a Yarn install warning. Sorry about the noise!
workspaces from our package.json to silence a Yarn warning (@timdorr)This release shrinks the size of our internal Subscription class, and updates useSelector to avoid an unnecessary selector call on mount.
This release shrinks the size of our internal Subscription class, and updates useSelector to avoid an unnecessary selector call on mount.
Our internal Subscription implementation has been written as a class ever since it was added in v5. By rewriting it as a closure factory, we were able to shave a few bytes off the final bundle size.
useSelector Mount OptimizationA user noticed that useSelector had never been given an early "bail out if the root state is the same" check to match how connect works. This resulted in a usually-unnecessary second call to the provided selector on mount. We've added that check.
We've consolidated the list of exported public APIs into a single file, and both the index.js and alternate-renderers.js entry points now re-export everything from that file. No meaningful change here, just shuffling lines of code around for consistency.
With the announcement of React 18, we've been working with the React team to plan our migration path to keep React-Redux fully compatible with React's upcoming features.
We've already migrated the React-Redux main development branch to TypeScript, and are prototyping compatibility implementation updates. We'd appreciate any assistance from the community in testing out these changes so that we can ensure React-Redux works great for everyone when React 18 is ready!
Our master branch now uses Yarn v2 for package management, is built with TypeScript, and we've made CI updates to test against multiple TS versions.
The 7.x branch has also been updated to use Yarn v2 for consistency.
These only affect contributors to the React-Redux package itself.
https://github.com/reduxjs/react-redux/compare/v7.2.4...v7.2.5
This release drops our dependency on the core redux package by inlining bindActionCreators, and tweaks useSelector to ensure that selectors aren't run
This release drops our dependency on the core redux package by inlining bindActionCreators, and tweaks useSelector to ensure that selectors aren't run an extra time while re-rendering.
React-Redux has always imported the bindActionCreators utility from the core redux package for use in connect. However, that meant that we had to have a peer dependency on redux, and this was the only reason we actually required that redux be installed. This became more annoying with the arrival of Redux Toolkit, which has its own dependency on redux internally, and thus users typically saw peer dependency warnings saying that "redux isn't listed as a dependency in your app".
Code reuse across separate packages is a great thing, but sometimes the right thing to do is duplicate code. So, we've inlined bindActionCreators directly into React-Redux, and we've completely dropped the dependency on Redux. This means that React-Redux will no longer produce a peerDep warning when used with Redux Toolkit, and <Provider> and connect really only need a Redux-store-compatible value to work right.
useSelector FixesUsers reported that useSelector was re-running selector functions again unnecessarily while rendering after a dispatch. We've tweaked the logic to ensure that doesn't happen.
useSelector also now has checks in development to ensure that selector and equalityFn are functions.
https://github.com/reduxjs/react-redux/compare/v7.2.3...v7.2.4
This release improves behavior in useSelector by returning the existing reference if the newly returned selector result passes the equality check, and
This release improves behavior in useSelector by returning the existing reference if the newly returned selector result passes the equality check, and adds a hard dependency on the @types/react-redux package to ensure TS users always have the typedefs installed.
useSelector Results ReuseIssue #1654 reported that useSelector was returning new references from a selector even if the equality comparison function returned true. This is because the equality check was only ever being performed during the action dispatch process.
We now run the equality comparison against the value calculated by the selector while rendering, and return the existing reference for consistency if the old and new values are considered equal. This should improve some cases where further derived values where being recalculated unnecessarily.
React-Redux has always been written in plain JS, and the typedefs maintained by the community in DefinitelyTyped. We plan on eventually rewriting the library in TypeScript in a future React-Redux v8 release, but until then the types can stay in DT.
However, having to always manually install @types/react-redux is annoying, and some users have gotten confused by that. This release adds a hard dependency on @types/react-redux, so that if you install react-redux, you automatically get the types as well. This should simplify the process for TS users.
We've made several docs updates recently:
We are currently working on a new React-Redux tutorial that will teach the React-Redux hooks as the primary approach, based on the "UI and React" page in the Redux docs "Fundamentals" tutorial.
https://github.com/reduxjs/react-redux/compare/v7.2.2...v7.2.3
This release allows you to use React Redux with React 17 without a warning when installing. That's about it.
This release allows you to use React Redux with React 17 without a warning when installing. That's about it.
This release improves useSelector value display in the React DevTools, fixes a potential race condition, and fixes a couple additional minor issues.
This release improves useSelector value display in the React DevTools, fixes a potential race condition, and fixes a couple additional minor issues.
useSelector DevTools DisplayThe React DevTools normally show custom hooks with their inspected name (such as "Selector" for useSelector), and any calls to core hooks inside. This is not always informative, so React has the useDebugValue hook to allow custom hooks to specify what value should be shown instead.
useSelector now calls useDebugValue to specifically show the current selected value instead of its internal hooks usage.
This release has a few different bug fixes:
reactReduxForwardedRef to avoid a rare situation where someone else might be passing down a field named forwardedRefuseSelector error messageThis release fixes two bugs, an algorithmic problem with unsubscribing components and a memory leak with connect. It also has optimizations for produc
This release fixes two bugs, an algorithmic problem with unsubscribing components and a memory leak with connect. It also has optimizations for production bundle size, and adds a couple small improvements to developer readability while debugging.
connect in v7 is implemented using hooks, and the hooks usage captures numerous values from the surrounding scope. We received a PR informing us that the way we were capturing these values would likely result in a copy of the first version of its props being kept alive indefinitely.
This memory leak has been fixed by extracting a custom hook that receives all the necessary values as arguments, so that they're not captured via closure.
We also received a PR letting us know that the unsubscribe logic had a quadratic algorithm in it, as removing a subscriber would use an indexOf(listener) check to remove that callback. If there were a large number of subscribers, that line's runtime would increase rapidly, causing slowdowns.
This algorithm has been replaced with tracking subscribers via a linked list, which drastically improves the runtime of this section of the code even with large numbers of subscribers.
Thanks to @larrylin28 and @wurstbonbon for finding these bugs and submitting PRs to fix them!
We've made a number of small tweaks to the codebase to improve the ability of bundlers to shake and minimize the final included size in a bundle. The net result is that react-redux@7.2.0 is smaller than 7.1.3, dropping 1.3K min and 0.6K min+gzip. (In fact, it's even smaller than the pre-hooks 7.0.0 when gzipped!)
Thanks to @Andarist for doing most of the work on this!
The ReactReduxContext instance now has a displayName set, so it should show up in the React DevTools as ReactRedux.Provider.
Also, when an error is caught in useSelector and re-thrown, we now append the original stack trace.
Thanks to @pieplu and @r3dm1ke for these!
UseEffect (@larrylin28 - #1506)Forgot to remove a console statement before I published 7.1.2. Oops!
Forgot to remove a console statement before I published 7.1.2. Oops!
Lint your source code before publishing, folks.
This releases fixes a subtle timing bug with connect and useSelector in React Native environments, and adds the ability to pass through non-Redux-stor
This releases fixes a subtle timing bug with connect and useSelector in React Native environments, and adds the ability to pass through non-Redux-store values as a store prop.
Our current implementation requires cascading updates down through connected components. This is primarily done during React's "commit phase" via the useLayoutEffect hook. Unfortunately, React warns when useLayoutEffect is called in SSR environments, so we try to feature-detect that and fall back to useEffect just to avoid that warning.
Unfortunately, a tweak to the feature detection conditions during the pre-7.1.0 work caused the check to accidentally fail in React Native environments. This meant that useEffect was actually being used all the time, and this led to occasional timing bugs such as #1313 and #1437 . This affected the previous v7.1.x releases.
We've fixed that issue, and added additional test cases to ensure that our code works correctly under React Native.
See #1444 for more details on the feature detection and the fix.
connect has always accepted passing a Redux store directly to connected components as a prop named store (with the exception of v6). As a result, the store prop has effectively been treated as a "reserved" prop, in much the same way that key and ref are "reserved" prop names handled by React.
Some users may be using the word "store" to describe their domain data, and have asked to allow variables that aren't a Redux store through the store prop to the component (#1393). We've finally been able to implement that capability.
store prop (@markerikson - #1447)latestStoreState field (@Hypnosphi - #1426)Nothing published for this version
This release includes some new APIs for those that want to use a custom React Context with our Hooks API, a small memory optimization, and has a fix f
This release includes some new APIs for those that want to use a custom React Context with our Hooks API, a small memory optimization, and has a fix for when the store changes on a Provider with incompatible children.
create*Hook factory APIs (#1309 by @ryaninvents)After much discussion, we've decided these Hook things are probably going to stick around, so we might as well add some. Many thanks to @MrWolfZ, @jos
After much discussion, we've decided these Hook things are probably going to stick around, so we might as well add some. Many thanks to @MrWolfZ, @josepot, @perrin4869, and @mpeyper for their contributions and to everyone else that offered feedback, ideas, and critiques as we built them out. Go open source!
deps argument to useSelector (#1251 by @MrWolfZ)useRedux (@markerikson)useActions (@markerikson)deps argument (#1272 by @josepot)shallowEqual with reference equality in useSelector (#1288 by @perrin4869)This version is essentially the same as the previous 7.1.0-alpha.5 release. But it has an rc tag on it, so you can more easily justify the upgrade to
⚠️We've got RC sign! ⚠️
This version is essentially the same as the previous 7.1.0-alpha.5 release. But it has an rc tag on it, so you can more easily justify the upgrade to your manager.
Get to it!
npm install react-redux@next
We're still making changes to our hooks APIs, but I'm hopeful that we're getting close to having the behavior nailed down.
We're still making changes to our hooks APIs, but I'm hopeful that we're getting close to having the behavior nailed down.
This release makes three specific changes to useSelector:
deps array has been removed. If you want to ensure the same selector function reference is used, you should memoize it yourself.=== check, instead of a shallow equality check.useSelector now accepts a comparison function as an optional second argument, similar to how React.memo() works conceptually. You may pass your own comparison function to customize how useSelector determines if a re-render is necessary.In addition, we now export our internal shallowEqual utility function. If you want to return to the prior equality behavior, you may pass that as the equality comparison function:
import { shallowEqual, useSelector } from "react-redux"
// later
const selectedData = useSelector(mySelector, shallowEqual)
The optional comparison function also enables using something like Lodash's _.isEqual() or Immutable.js's comparison capabilities.
Our previous alpha versions included both useSelector() (similar to mapState) and useActions() (similar to mapDispatch).
Our previous alpha versions included both useSelector() (similar to mapState) and useActions() (similar to mapDispatch).
However, Dan Abramov strongly suggested that we consider removing useActions(), as the idea of "binding action creators" is less relevant when using hooks, and also adds conceptual overhead and syntactic complexity. We requested feedback from alpha users, and the initial feedback agreed with Dan's suggestion.
Based on that feedback, v7.1.0-alpha.4 removes the useActions() hook. Instead, call useDispatch() in your component, and manually call dispatch(someActionCreator()) in callbacks and effects as needed.
If you still wish to use useActions(), the hooks alpha docs page has an implementation you can copy and paste into your own code.
After discussion in the hooks alpha feedback issue, we've decided to remove the useRedux() hook, as it doesn't really bring any benefits. If you were
After discussion in the hooks alpha feedback issue, we've decided to remove the useRedux() hook, as it doesn't really bring any benefits. If you were using it in your own code, replace the useRedux() call with separate calls to useSelector() and useActions().
This release also includes the timing bugfix from #1263.
Also, while you won't notice it, @mpeyper was able to simplify our hooks unit tests using react-hooks-testing-library.
Nothing published for this version
React hooks are cool. All the cool kids are adding hooks to their libraries. We wanna be cool too.
React hooks are cool. All the cool kids are adding hooks to their libraries. We wanna be cool too.
That's why React Redux now includes a set of hooks you can use as an alternative to connect()!
npm i react-redux@next
yarn add react-redux@next
This alpha release includes the following hooks:
useSelector(): extracts values from the Redux store state and subscribes to the store (similar to mapState)useActions(): binds action creators so that they dispatch actions when called (similar to mapDispatch)useRedux(): both extracts values and binds action creators (similar to connect())useDispatch(): returns the store dispatch methoduseStore(): returns the Redux store instanceFor more details, please see the "Hooks" API reference page under the "next" version section of the React Redux docs. In addition, issue #1179: Discussion: Potential hooks API design contains the history of how these APIs were designed.
Please try these hooks out in your own apps, and give us feedback on how well they work!
We've opened up issue #1252 as a thread for feedback and discussion of the alpha.
Note: The hook APIs listed in this page are still experimental and in alpha! Try them out, but be aware that they may be changed before a final release, including potential renaming or removal.
useSelector (#1251 by @MrWolfZ)Thanks to:
Initial alpha hooks release. See the release notes for v7.1.0-alpha.1 for details.
Initial alpha hooks release. See the release notes for v7.1.0-alpha.1 for details.
Your coding agent can read these notes before it upgrades. Set up the MCP server →