redux
5.0.1 · 23 Dec 2023MIT62.6M / weekRepositoryHomepagenpmAtom feed
68 stable releases, newest first, by release line. Notes are quoted as the maintainers published them.
- 5.x · latest line
5.0.1
23 Dec 2023isPlainObject: Support check Object.create(null)
types/store: Unexpectedly narrowed return type of function
Store['getState']
This patch release adjusts the
isPlainObjectutil to allow objects created viaObject.create(null), and fixes a type issue which accidentally made the store state type non-nullable.What's Changed
isPlainObject: Support check Object.create(null)
types/store: Unexpectedly narrowed return type of function
Store['getState']
5.0.0
4 Dec 2023- deprecated
Continues to mark
createStoreas deprecated - deprecated
Deprecates the
AnyActiontype in favor of anUnknownActiontype that is used everywhere - removed
Removes the
PreloadedStatetype in favor of a new generic argument for theReducertype.
This major release:
Converts the codebase to TypeScript
Updates the packaging for better ESM/CJS compatibility and modernizes the build output
Requires that
action.typemust be a string- deprecated
Continues to mark
createStoreas deprecated - deprecated
Deprecates the
AnyActiontype in favor of anUnknownActiontype that is used everywhere - removed
Removes the
PreloadedStatetype in favor of a new generic argument for theReducertype.
This release has breaking changes.
This release is part of a wave of major versions of all the Redux packages: Redux Toolkit 2.0, Redux core 5.0, React-Redux 9.0, Reselect 5.0, and Redux Thunk 3.0.
For full details on all of the breaking changes and other significant changes to all of those packages, see the "Migrating to RTK 2.0 and Redux 5.0" migration guide in the Redux docs.
Note
The Redux core, Reselect, and Redux Thunk packages are included as part of Redux Toolkit, and RTK users do not need to manually upgrade them - you'll get them as part of the upgrade to RTK 2.0. (If you're not using Redux Toolkit yet, please start migrating your existing legacy Redux code to use Redux Toolkit today!)
# RTK npm install @reduxjs/toolkit yarn add @reduxjs/toolkit # Standalone npm install redux yarn add redux
Changelog
ESM/CJS Package Compatibility
The biggest theme of the Redux v5 and RTK 2.0 releases is trying to get "true" ESM package publishing compatibility in place, while still supporting CJS in the published package.
The primary build artifact is now an ESM file,
dist/redux.mjs. Most build tools should pick this up. There's also a CJS artifact, and a second copy of the ESM file namedredux.legacy-esm.jsto support Webpack 4 (which does not recognize theexportsfield inpackage.json). Additionally, all of the build artifacts now live under./dist/in the published package.Modernized Build Output
We now publish modern JS syntax targeting ES2020, including optional chaining, object spread, and other modern syntax. If you need to
Build Tooling
We're now building the package using github.com/egoist/tsup. We also now include sourcemaps for the ESM and CJS artifacts.
Dropping UMD Builds
Redux has always shipped with UMD build artifacts. These are primarily meant for direct import as script tags, such as in a CodePen or a no-bundler build environment.
We've dropped those build artifacts from the published package, on the grounds that the use cases seem pretty rare today.
There's now a
redux.browser.mjsfile 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!
createStoreMarked DeprecatedIn Redux 4.2.0, we marked the original
createStoremethod as@deprecated. Strictly speaking, this is not a breaking change, nor is it new in 5.0, but we're documenting it here for completeness.This deprecation is solely a visual indicator that is meant to encourage users to migrate their apps from legacy Redux patterns to use the modern Redux Toolkit APIs.
The deprecation results in a visual strikethrough when imported and used, like
, but with no runtime errors or warnings.createStorecreateStorewill continue to work indefinitely, and will not ever be removed. But, today we want all Redux users to be using Redux Toolkit for all of their Redux logic.To fix this, there are three options:
- deprecated
Follow our strong suggestion to switch over to Redux Toolkit and
configureStore - deprecated
Do nothing. It's just a visual strikethrough, and it doesn't affect how your code behaves. Ignore it.
- deprecated
Switch to using the
legacy_createStoreAPI that is now exported, which is the exact same function but with no@deprecatedtag. The simplest option is to do an aliased import rename, likeimport { legacy_createStore as createStore } from 'redux'
Action types must be strings
We've always specifically told our users that actions and state must be serializable, and that
action.typeshould be a string. This is both to ensure that actions are serializable, and to help provide a readable action history in the Redux DevTools.store.dispatch(action)now specifically enforces thataction.typemust be a string and will throw an error if not, in the same way it throws an error if the action is not a plain object.In practice, this was already true 99.99% of the time and shouldn't have any effect on users (especially those using Redux Toolkit and
createSlice), but there may be some legacy Redux codebases that opted to use Symbols as action types.TypeScript Changes
We've dropped support for TS 4.6 and earlier, and our support matrix is now TS 4.7+.
Typescript rewrite
In 2019, we began a community-powered conversion of the Redux codebase to TypeScript. The original effort was discussed in #3500: Port to TypeScript, and the work was integrated in PR #3536: Convert to TypeScript.
However, the TS-converted code sat around in the repo for several years, unused and unpublished, due to concerns about possible compatibility issues with the existing ecosystem (as well as general inertia on our part).
Redux core v5 is now built from that TS-converted source code. In theory, this should be almost identical in both runtime behavior and types to the 4.x build, but it's very likely that some of the changes may cause types issues.
Please report any unexpected compatibility issues!!
AnyActiondeprecated in favour ofUnknownActionThe Redux TS types have always exported an
AnyActiontype, which is defined to have{type: string}and treat any other field asany. This makes it easy to write uses likeconsole.log(action.whatever), but unfortunately does not provide any meaningful type safety.We now export an
UnknownActiontype, which treats all fields other thanaction.typeasunknown. This encourages users to write type guards that check the action object and assert its specific TS type. Inside of those checks, you can access a field with better type safety.UnknownActionis now the default any place in the Redux source that expects an action object.AnyActionstill exists for compatibility, but has been marked as deprecated.Note that Redux Toolkit's action creators have a
.match()method that acts as a useful type guard:if (todoAdded.match(someUnknownAction)) { // action is now typed as a PayloadAction<Todo> }You can also use the new
isActionutil to check if an unknown value is some kind of action object.Middlewaretype changed - Middlewareactionandnextare typed asunknownPreviously, the
nextparameter is typed as theDtype parameter passed, andactionis typed as theActionextracted from the dispatch type. Neither of these are a safe assumption:nextwould be typed to have all of the dispatch extensions, including the ones earlier in the chain that would no longer apply.Technically it would be mostly safe to type
nextas the default Dispatch implemented by the base redux store, however this would causenext(action)to error (as we cannot promiseactionis actually anAction) - and it wouldn't account for any following middlewares that return anything other than the action they're given when they see a specific action.
actionis not necessarily a known action, it can be literally anything - for example a thunk would be a function with no.typeproperty (soAnyActionwould be inaccurate)
We've changed
nextto be(action: unknown) => unknown(which is accurate, we have no idea whatnextexpects or will return), and changed theactionparameter to beunknown(which as above, is accurate).In order to safely interact with values or access fields inside of the
actionargument, you must first do a type guard check to narrow the type, such asisAction(action)orsomeActionCreator.match(action).This new type is incompatible with the v4
Middlewaretype, so if a package's middleware is saying it's incompatible, check which version of Redux it's getting its types from!PreloadedStatetype removed in favour ofReducergenericWe've made tweaks to the TS types to improve type safety and behavior.
First, the
Reducertype now has aPreloadedStatepossible generic:type Reducer<S, A extends Action, PreloadedState = S> = ( state: S | PreloadedState | undefined, action: A ) => S
Per the explanation in #4491:
Why the need for this change? When the store is first created by
createStore/configureStore, the initial state is set to whatever is passed as thepreloadedStateargument (orundefinedif nothing is passed). That means that the first time that the reducer is called, it is called with thepreloadedState. After the first call, the reducer is always passed the current state (which isS).For most normal reducers,
S | undefinedaccurately describes what can be passed in for thepreloadedState. However thecombineReducersfunction allows for a preloaded state ofPartial<S> | undefined.The solution is to have a separate generic that represents what the reducer accepts for its preloaded state. That way
createStorecan then use that generic for itspreloadedStateargument.Previously, this was handled by a
$CombinedStatetype, but that complicated things and led to some user-reported issues. This removes the need for$CombinedStatealtogether.This change does include some breaking changes, but overall should not have a huge impact on users upgrading in user-land:
The
Reducer,ReducersMapObject, andcreateStore/configureStoretypes/function take an additionalPreloadedStategeneric which defaults toS.The overloads for
combineReducersare removed in favor of a single function definition that takes theReducersMapObjectas its generic parameter. Removing the overloads was necessary with these changes, since sometimes it was choosing the wrong overload.Enhancers that explicitly list the generics for the reducer will need to add the third generic.
Other Changes
Internal Listener Implementation
The Redux store has always used an array to track listener callbacks, and used
listeners.findIndexto remove listeners on unsubscribe. As we found in React-Redux, that can have perf issues when many listeners are unsubscribing at once.In React-Redux, we fixed that with a more sophisticated linked list approach. Here, we've updated the
listenersto be stored in aMapinstead, which has better delete performance than an array.In practice this shouldn't have any real effect, because React-Redux sets up a subscription in
<Provider>, and all nested components subscribe to that. But, nice to fix it here as well.isActionPredicateWe recently added an
isActionpredicate to RTK, then realized it's better suited for the Redux core. This can be used anywhere you have a value that could be a Redux action object, and you need to check if it is actually an action. This is specifically useful for use with the updated Redux middleware TS types, where the default value is nowunknownand you need to use a type guard to tell TS that the current value is actually an action:We've also exported the
isPlainObjectutil that's been in the Redux codebase for years as well.What's Changed
Entirely too many PRs to list here, as it's been a few years since 4.2 was released :) See the diff below.
- 4.x
4.2.1
28 Jan 2023Remove minified check
This bugfix release removes the
isMinifiedinternal check to fix a compat issue with Expo. That check has added in early 2016, soon after Redux 3.0 was released, at a time when it was still less common to use bundlers with proper production build settings. Today that check is irrelevant, so we've removed it.What's Changed
Remove minified check
4.2.0
18 Apr 2022- deprecated
Mark
createStoreas deprecated, and addlegacy_createStorealias RTK provides a vastly improved Redux usage experience, with APIs that simplify standard usage patterns and eliminate common bugs like accidental mutations
We've had suggestions to merge all of RTK into the
reduxcore package, or fully deprecate the entirereduxpackage and rename it to@reduxjs/core. Unfortunately, those bring up too many complexities:
This release marks the original
createStoreAPI as@deprecatedto encourage users to migrate to Redux Toolkit, and adds a newlegacy_createStoreAPI as an alias without the deprecation warning.Goal
Redux Toolkit (the
@reduxjs/toolkitpackage) is the right way for Redux users to write Redux code today:redux.js.org/introduction/why-rtk-is-redux-today
Unfortunately, many tutorials are still showing legacy "hand-written" Redux patterns, which result in a much worse experience for users. New learners going through a bootcamp or an outdated Udemy course just follow the examples they're being shown, don't know that RTK is the better and recommended approach, and don't even think to look at our docs.
Given that, the goal is to provide them with a visual indicator in their editor, like
createStore. When users hover over thecreateStoreimport or function call, the doc tooltip recommends usingconfigureStorefrom RTK instead, and points them to that docs page. We hope that new learners will see the strikethrough, read the tooltip, read the docs page, learn about RTK, and begin using it.To be extremely clear:
WE ARE NOT GOING TO ACTUALLY REMOVE THE
createStoreAPI, AND ALL YOUR EXISTING CODE WILL STILL CONTINUE TO WORK AS-IS!We are just marking
createStoreas "deprecated":"the discouragement of use of some feature or practice, typically because it has been superseded or is no longer considered efficient or safe, without completely removing it or prohibiting its use"
For additional details, see the extensive discussion in #4325 .
Rationale
RTK provides a vastly improved Redux usage experience, with APIs that simplify standard usage patterns and eliminate common bugs like accidental mutations
We've had suggestions to merge all of RTK into the
reduxcore package, or fully deprecate the entirereduxpackage and rename it to@reduxjs/core. Unfortunately, those bring up too many complexities:We already had a package rename from
redux-starter-kitto@reduxjs/toolkit, and all of our docs and tutorials have pointed to it for the last three years. I don't want to put users through another whiplash package transition for no real benefitMerging or rearranging our packages would effectively require merging all of the Redux repos into a single monorepo. That would require hundreds of hours of effort from us maintainers, including needing to somehow merge all of our docs sites together. We don't have the time to do that.
I don't want to add runtime warnings that would be really annoying
So, this is the minimum possible approach we can take to reach out to users who otherwise would never know that they are following outdated patterns, while avoiding breaking running user code or having to completely rewrite our package and repo structure.
Results
When a user imports
createStorein their editor, they will see a visual strikethrough. Hovering over it will show a doc tooltip that encourages them to useconfigureStorefrom RTK, and points to an explanatory docs page:image
Again, no broken code, and no runtime warnings.
If users do not want to see that strikethrough, they have three options:
Follow our suggestion to switch over to Redux Toolkit and
configureStoreDo nothing. It's just a visual strikethrough, and it doesn't affect how your code behaves. Ignore it.
Switch to using the
legacy_createStoreAPI that is now exported, which is the exact same function but with no@deprecationtag. The simplest option is to do an aliased import rename:
image
What's Changed
- deprecated
Mark
createStoreas deprecated, and addlegacy_createStorealias
4.1.2
28 Oct 2021Fix preloaded state type
This release fixes a small specific TS types issue where state types that had a nested
unknownfield inside would cause compilation failures when used as thepreloadedStateargument.What's Changed
Fix preloaded state type
4.1.0
24 Apr 2021Remove symbol-observable and loose-envify deps (#4058 - @markerikson)
Port error extraction setup from master (#4057 - @markerikson)
Port build dependencies from master into 4.x (#4056 - @markerikson)
This release shrinks our bundle size via error message extraction, updates several error messages for clarity, and optimizes our list of runtime dependencies.
Overall, version 4.1 shrinks from 2.6K min+gz to 1.6K min+gz thanks to these changes.
Be sure to check out the Redux Toolkit 1.6 alpha containing our new "RTK Query" data fetching APIs! It also includes Redux 4.1 as a dependency.
Changelog
Error Message Extraction and Improvements
We now extract all of our error messages from production builds in order to save on bundle size, using a technique inspired from React's error code extraction. The error messages will still show as normal in development, but in production they will reference a specific numeric error code and provide a link to a Redux docs page that has the full error message.
An example of this is: redux.js.org/errors , which shows the "can't subscribe while reducers are executing" error.
The error code extraction saves about 800 bytes out of a production build.
We've also updated many of our error messages to provide additional details at runtime about what happened, especially runtime type checks such as "actions must be plain objects". They now provide a more specific type for the unexpected value, such as indicating
promiseorfunction:expect(() => store.dispatch(() => {})).toThrow( /the actual type was: 'function'/ ) expect(() => store.dispatch(new Date())).toThrow( /the actual type was: 'date'/ )Dependency Updates
We've updated the list of runtime dependencies for Redux:
Typing Tweaks
We've merged fixes for a couple edge cases in the 4.x TS typings related to state types.
Remove symbol-observable and loose-envify deps (#4058 - @markerikson)
Port error extraction setup from master (#4057 - @markerikson)
Port build dependencies from master into 4.x (#4056 - @markerikson)
Rewrite Redux core error messages (#4055 - @markerikson)
Mangle error codes to error indexes (#3920 - @andrewmcgivery)
Declare "EmptyObject" interface to wrap $CombinedState (#4031 - @JacobLey)
Only apply mapped types to un-branded types (#3805 - @invliD)
4.0.5
24 Dec 2019Clear current listeners on store unsubscribe
Fix for combineReducers when replaceReducers removes a reducer
TypeScript: Add strict type inference overload for combineReducers
This release includes a memory leak fix, and a fix for removing reducers with replaceReducer and combineReducers.
There are also some TypeScript changes, which require version 3.5 or higher. This also removes our
DeepPartialtype, which wasn't intended to be a public API. If you need this type, you can find an equivalent of likely higher quality in theutility-typespackage.Speaking of TypeScript, we are done with converting the code to TypeScript on
masterand are looking to get some TS improvements in before launching 5.0. If you're interested in helping, feel free to submit a PR with anything you'd like to contribute.Clear current listeners on store unsubscribe
Fix for combineReducers when replaceReducers removes a reducer
TypeScript: Add strict type inference overload for combineReducers
TypeScript: Preloaded state is now selectively partial (instead of deeply partial)
4.0.3
9 Jul 2019Reverts the change to
combineReducers' type parameters
This is a quick revert of a change to our typings that broke compatibility. Apologies for the problems.
Also, if you are experiencing type errors related to
[Symbol.observable], please ensure you have the same version of redux installed for all your dependencies withnpm ls redux.Reverts the change to
combineReducers' type parameters
4.0.2
9 Jul 2019Iterate in combineReducers using
for inFix
DeepPartialtypeAdd types for Observable interface
This is a very minor release with some nice improvements to our TypeScript type definitions. Enjoy!
Iterate in combineReducers using
for inFix
DeepPartialtypeAdd types for Observable interface
Make reducer optional in JSDocs
Infer action types from
combineReducers
4.0.1
13 Oct 2018Update mixed NODE_ENV message for Webpack 4 (4a215fb
Add unpkg field to package.json
Use same return type for both StoreCreator signatures
A very minor release. We've upgraded to Babel 7 internally and now provide a
.mjsfile which you can import cleanly into browsers that support ES modules natively. Enjoy!4.0.0
17 Apr 2018- removed
Remove @private flag on AnyAction type definition
Tons of docs updates. Thanks @markerikson and the Redux community for all your PRs!
Make middleware API dispatch pass through all call arguments
Redux 4 is here! 🎉
If you're a React user, this is going to be a lot like going from 15 to 16. Not a lot of user-facing changes, but some interesting improvements under the hood.
The major changes (#1342) are around our TypeScript definitions, bundled CommonJS and ES builds, throwing if you subscribe or getState from a reducer, and a bunch of other smaller things. The full changes are listed below.
Enjoy!
Tons of docs updates. Thanks @markerikson and the Redux community for all your PRs!
Make middleware API dispatch pass through all call arguments
Refactor applyMiddleware to reduce confusion around createStore args
Make bindActionCreators transparently pass
this- removed
Remove @private flag on AnyAction type definition
Fixed quote types inconsistency in a warning message
Move ActionTypes to a private export (b62248b
Throw if getState, subscribe, or unsubscribe called while dispatching (including inside a reducer)
Warn when dispatching during Middleware setup
Mapped type for combineReducers in index.d.ts
Remove legacy jsnext entry
Revamp TypeScript typing with more type safety
Fix TS definitions test for new Dispatch typing
Add DeepPartial type for preloaded state
Bundle cjs and es formats
REPLACE action for replaceReducers
Update build to use babel-preset-env
Optimize dispatch plain object check
Update TypeScript typings
Added prettier formatting
Add a sideEffects: false flag for Webpack 4
Fix missed case in "observe" type check
- 3.x
3.7.2
13 Jul 2017Fixed the definition of 'Reducer' for TypeScript 2.4.
3.7.1
26 Jun 2017This reverts the
console.erroronbindActionCreators()coming from #2279.This reverts the
console.erroronbindActionCreators()coming from #2279.While well-intentioned, when star importing all exports from a module (
import * as actions from './actions'), transpilation by Babel defaults to adding adefaultand__esModuleproperty to the import, which are not functions. While it can be disabled, this isn't common to do and leads to a lot of confusion. So, we're reverting the change.Thanks for the feedback from everyone and the civility and healthy discourse on the issue!
3.7.0
17 Jun 2017Build UMD with rollup
Warn when bindActionCreators encounters non-function property
Remove filtering inside compose
Another long break!
Oh, hey! I didn't see you sitting there. You look bored. How about a Redux release to spice things up?
Not a huge set of changes to report here. The biggest change, and the reason for the minor bump, is the UMD build is now done via Rollup. One big advantage is more readable code in the bundle. Rollup does "scope hoisting", which is a fancy term for putting every module at the top level of the file. Other than a surrounding IIFE, all of the code in Redux all lives together. You can compare the two here:
Rollup UMD build
vs
Webpack UMD buildThere is also a cost savings of 30,811 vs 26,880 bytes, and 6,999 vs 5,995 bytes minified. Redux is already a small library, and this helps shave some extra bytes for our UMD users.
One thing to note is that Webpack has introduced it's own scope hoisting feature in 3.0 beta. So, this isn't intended as an indictment of Webpack. You should continue to use it in your own apps. The adage of "Webpack is for apps, Rollup is for libraries" definitely holds true. It still has a superior developer experience with hot module reloading and webpack-dev-server. But use whatever makes sense for your project, not just whatever we use. 😄
We're also looking at applying this to the NPM bundle. The main motivation is again more readable code in your bundles. Instead of transpilation oddities from Babel, you will end up with a single clean file, which should be easier to read through and debug. It's currently scheduled for the big, mythical 4.0 release and you can follow along in #2358
Build UMD with rollup
Warn when bindActionCreators encounters non-function property
Remove filtering inside compose
Simplify compose
3.6.0
4 Sep 2016Added a Redux logo
Replace es3ify with Babel ES3 transforms
Hey, it's been a while!
How's everyone doing? Enjoying your summer (or winter for the Southern Hemisphere folks)?
This is a bugfix release for Redux. We're working towards a 4.0 with more substantial changes. Please see #1342 to pitch in!
Dan also ported all the examples (except the universal one) in #1883 to use the excellent Create React App. This means the changes in #1800 have been lost. If you'd like to help out, we would love PRs on the examples to modernize and clean them up.
Changes
Added a Redux logo
Replace es3ify with Babel ES3 transforms
Run tests on Node 6
Optimize one function case in compose
Check ES3 syntax compatibility
TypeScript: preloadedState is optional
Add a warning for undefined properties passed to combineReducers
Add module entry point for webpack 2
TypeScript: Improve typings for compose function
3.5.2
24 Apr 2016Enforces a newer version of
symbol-observablethat works in IE8
3.5.0
20 Apr 2016Adds interop with observable libraries
3.3.1
6 Feb 2016ES Modules build now uses the ES Modules build of Lodash. This makes vanilla Redux code include zero CommonJS interop for Rollup users.
3.3.0
5 Feb 2016Fixes
jsnext:mainto point to a Rollup-friendly ES Modules build inredux/es. It still depends on Lodash so you can’t use withoutrollup-plugin-commonjs, but importing individual functions likeimport { createStore } from 'redux'should now work, and you shouldn’t be getting an error when you usenpm({ jsnext: true })anymore due to a brokenjsnext:main. (#1369, #1042, #1327)
3.1.6
31 Jan 2016subscribe()now throws a descriptive error when thelistenerargument is not a functionbindActionCreators()now ignores anything but functions on the input object
3.1.3
29 Jan 2016Don’t crash when
consoleorconsole.erroris unavailable
3.1.0
28 Jan 2016For Browserify users, Redux should now be properly envified without extra configuration
createStore()now receives an enhancer such asapplyMiddleware()as the last optional argument
For Browserify users, Redux should now be properly envified without extra configuration
createStore()now receives an enhancer such asapplyMiddleware()as the last optional argument
Wait, what?
You don’t have to change anything. However if you use store enhancers such as
applyMiddleware()or Redux DevTools you might like that you can now express the same code in a more JavaScript-friendly way:- const createStoreWithMiddleware = applyMiddleware( - thunk, - logger - )(createStore) - const store = createStoreWithMiddleware( - rootReducer, - initialState - ) + const store = createStore( + rootReducer, + initialState, + applyMiddleware(thunk, logger) + )
For multiple store enhancers you can still use
compose()but in a similar more straightforward fashion:- const finalCreateStore = compose( - applyMiddleware(thunk, logger), - DevTools.instrument() - )(createStore) - const store = finalCreateStore(reducer, initialState) + const store = createStore( + reducer, + initialState, + compose( + applyMiddleware(thunk, logger), + DevTools.instrument() + ) + )
The second
initialStateargument stays optional so you can skip it when specifying the enhancer.The old way of doing things still works, too.
We’re just adding a nicer way to apply enhancers, that’s all.Happy reducing!
3.0.6
25 Jan 2016- breaking
Now we warn if you’re running an unenvified build of Redux in production as it is slower. We determine this by checking whether you have uglified Redux code, and if you did, we check that
process.env.NODE_ENVpolyfill (which we require anyway) is set to'production'. This does not affect the UMD builds. This is also a warning and not a hard error so it isn't a breaking change. (#1029, #1075) The dev-only state shape sanity check warning in
combineReducers()now runs faster. (#1118)
compose()now aligns more closely with Underscore/Lodash behavior by allowing multiple arguments to be passed to the last function. This is not changing the existing behavior for the single argument call which has been the only possible use case before. (#632, #1050)The dev-only state shape sanity check warning in
combineReducers()now runs faster. (#1118)- breaking
Now we warn if you’re running an unenvified build of Redux in production as it is slower. We determine this by checking whether you have uglified Redux code, and if you did, we check that
process.env.NODE_ENVpolyfill (which we require anyway) is set to'production'. This does not affect the UMD builds. This is also a warning and not a hard error so it isn't a breaking change. (#1029, #1075) We now officially support importing individual modules from
redux/lib/*.js. This is only true for top-level directory—we do not supporting reaching intoredux/lib/utils, for example. To support this, we moved all top-level exports to be inredux/lib, for example,redux/lib/applyMiddleware.js. (#1223, #1224)
3.0.2
26 Sep 2015An error thrown inside reducer during the
combineReducer()sanity check will be delayed until the first dispatch. This lets Redux DevTools correctly handle it and recover from the error. (#717, #761, #807, gaearon/redux-devtools#106, gaearon/redux-devtools#120)
One of the problems v3.0.1 was intended to solve was not completely fixed in 3.0.1.
This release amends that.An error thrown inside reducer during the
combineReducer()sanity check will be delayed until the first dispatch. This lets Redux DevTools correctly handle it and recover from the error. (#717, #761, #807, gaearon/redux-devtools#106, gaearon/redux-devtools#120)
To enjoy this, you’ll need at least
redux-devtools@2.1.4.3.0.1
25 Sep 2015In development,
combineReducers()now checks the state shape on every invocation instead of just once. This makes it easy to discover issues like #715 where you post-process the state fromcombineReducers()and then wonder why something you added to it has disappeared after the next action. This change has no effect in production, and you’re unlikely to hit it in development either, as post-processing state fromcombineReducers()isn't a very common pattern. (#715, #720)The reducer probing performed by
combineReducers()as a sanity check has been moved from thecombineReducers()call to the first reducer invocation. Technically the check is still performed during thecombineReducers()call, but the error is only thrown after during the initial dispatch. (Usually that would correspond to thecreateStore()call.) This reason for this is that otherwise an error thrown inside a reducer used to blow upcombineReducers()and thus the whole module definition, and hot reloading used to fail in this case instead of showing the error in Redux DevTools. With this change and a corresponding fix in Redux DevTools, an error thrown inside a reducer that was later wrapped incombineReducers()will be displayed correctly, and once you fix the error, it will hot reload. (#717, #761, #106, #120)The reducer probing performed by
combineReducers()as a sanity check now uses@@redux/PROBE_UNKNOWN_ACTION_prefix in the action type. Previously, action type was a random string. The reason for this change is to make it easier for type-checking libraries like redux-tcomb ignore such actions. This change does not affect application developers: just like before, you should never attempt to handle@@redux/*actions directly in your code. (#792, #796)
This release brings a few changes that, while aimed at making the developer experience better, should have no noticeable impact on your apps.
In development,
combineReducers()now checks the state shape on every invocation instead of just once. This makes it easy to discover issues like #715 where you post-process the state fromcombineReducers()and then wonder why something you added to it has disappeared after the next action. This change has no effect in production, and you’re unlikely to hit it in development either, as post-processing state fromcombineReducers()isn't a very common pattern. (#715, #720)The reducer probing performed by
combineReducers()as a sanity check has been moved from thecombineReducers()call to the first reducer invocation. Technically the check is still performed during thecombineReducers()call, but the error is only thrown after during the initial dispatch. (Usually that would correspond to thecreateStore()call.) This reason for this is that otherwise an error thrown inside a reducer used to blow upcombineReducers()and thus the whole module definition, and hot reloading used to fail in this case instead of showing the error in Redux DevTools. With this change and a corresponding fix in Redux DevTools, an error thrown inside a reducer that was later wrapped incombineReducers()will be displayed correctly, and once you fix the error, it will hot reload. (#717, #761, #106, #120)The reducer probing performed by
combineReducers()as a sanity check now uses@@redux/PROBE_UNKNOWN_ACTION_prefix in the action type. Previously, action type was a random string. The reason for this change is to make it easier for type-checking libraries like redux-tcomb ignore such actions. This change does not affect application developers: just like before, you should never attempt to handle@@redux/*actions directly in your code. (#792, #796)
Happy reducing!
- 2.x
2.0.0
1 Sep 2015It was only needed because React Redux used it to magically allow reducer hot reloading. This magic used to cause problems (#301, #340), so we made the usage of
replaceReducer()for hot reloading explicit (#667).Breaking Changes
getReducer()is removed from Store public API (#668)It was only needed because React Redux used it to magically allow reducer hot reloading. This magic used to cause problems (#301, #340), so we made the usage of
replaceReducer()for hot reloading explicit (#667).It is likely that you never used
getReducer(). However, if you used hot reloading of reducers, you'll need to addmodule.hotAPI calls to the place where you create the store. (Of course, assuming that you use Webpack.)Before
import { createStore } from 'redux'; import rootReducer from '../reducers/index'; export default function configureStore(initialState) { return createStore(rootReducer, initialState); }After
import { createStore } from 'redux'; import rootReducer from '../reducers/index'; export default function configureStore(initialState) { const store = createStore(rootReducer, initialState); if (module.hot) { // Enable Webpack hot module replacement for reducers module.hot.accept('../reducers', () => { const nextRootReducer = require('../reducers/index'); store.replaceReducer(nextRootReducer); }); } return store; }This is more code, but what's happening is now explicit, and this also lets you do this right in
index.jsinstead of creating a separate<Root>component. See #667 for a migration example.compose()now acts like a propercompose()(#669)This fixes the embarrassing mishap that
compose()API was.
As suggested by @jlongster, now it is a propercompose()you'd find in Lodash or Underscore:it('composes from right to left', () => { const double = x => x * 2; const square = x => x * x; expect(compose(square)(5)).toBe(25); expect(compose(square, double)(5)).toBe(100); expect(compose(double, square, double)(5)).toBe(200); });In terms of usage, you just need to remove
createStorefrom the chain, and add it as a function application instead.Before
const finalCreateStore = compose( applyMiddleware(stuff), devTools(), somethingElse(), createStore );
After
const finalCreateStore = compose( applyMiddleware(stuff), devTools(), somethingElse() )(createStore);
process.env.NODE_ENVis required for CommonJS build (#671)In 1.0.1, we temporarily removed the dependency on it to support React Native, but now that RN 0.10 is out with
process.env.NODE_ENVpolyfill, we again demand it to be defined. If you're not ready to use RN 0.10, or are in a different environment, either use a browser build, or shim it yourself.- 1.x
1.0.0
14 Aug 2015- breaking
If
dispatchis attempted while reducer is executing, an error is thrown. Note that you can dispatch from lifecycle hooks just fine. It's only reducers that are not allowed to dispatch. (#368) Unsubscribing during a dispatch is now fixed: #462
bindActionCreatorsnow can also accept a function as the first argument: #352
Breaking Changes
If you're migrating from 0.12, apply 0.12 -> 1.0.0-alpha migration first, and then 1.0.0-alpha -> 1.0.0-rc. 1.0 only has a single breaking change since 1.0.0-rc:
- breaking
If
dispatchis attempted while reducer is executing, an error is thrown. Note that you can dispatch from lifecycle hooks just fine. It's only reducers that are not allowed to dispatch. (#368)
New Home
We moved under rackt Github org. This won't affect you, but the new official URL is github.com/rackt/redux. We did this because we share values, and we want to collaborate on creating better tools, libraries, documentation, and examples. Redux stays independent of React, but we will work closely with React Router community to figure out a better integration.
Docs!
We have real docs now. There are a few missing pieces, but it's a terrific effort, so thanks to everybody who contributed in the past month to get this shipped. Thanks to Gitbook for providing great tooling, too.
Examples!
There's been no shortage of great examples in Awesome Redux, but we're shipping two new built-in examples in 1.0. One of them is a very simple async application. Creating it is covered in async tutorial. Another example we ship is a “real-world” example. It's a port of somewhat well-known flux-react-router-example to Redux, and shows advanced techniques such as caching, data normalization, custom API middleware, and pagination. Hopefully this example will help answer some commonly asked questions.
Other Improvements
Unsubscribing during a dispatch is now fixed: #462
bindActionCreatorsnow can also accept a function as the first argument: #352Dispatching from iframe now works: #304
Symbols can be used as action types: #295 (Note: we don't recommend you to do this, because they're not serializable, so you can't record/replay user sessions.)
Patrons
The work on Redux was funded by the community.
Meet some of the outstanding companies and individuals that made it possible:- 0.12.x
0.12.0
19 Jun 2015Classes returned by decorators now expose a static
DecoratedComponentproperty for easier testingDependencies on
lodashandbabel-runtimeare droppedNow compatible with Babel loose mode
No breaking changes this time.
Classes returned by decorators now expose a static
DecoratedComponentproperty for easier testingDependencies on
lodashandbabel-runtimeare droppedNow compatible with Babel loose mode
composeStorenow ignores non-function values (useful in Babel loose mode)A UMD build is added
The initial action dispatched to the stores now has a built-in
@@INITtype (might be useful to devtools)
- 0.11.x
0.11.1
16 Jun 2015Bugfix: When
Connectorselectproperty changes, the state did not recalculate
0.11.0
14 Jun 2015Renames
composeroot export tocomposeMiddlewareto clarify the intentFixes a bug with
getStatereturning stale state after a hot reload
- 0.10.x
0.10.1
13 Jun 2015Connectornow throws ifselectreturns something other than a plain object (#85)The custom dispatcher API is tweaked so
setStatenow returns the state that was actually set. This makes custom dispatchers more composable. (#77)
Missing from the 0.10 release notes: React Native is now supported!
(And that's actually a breaking change.)Now, to import React-specific parts (containers or decorators), you need to either import from
redux/reactorredux/react-native:// Import utilities and functions from redux import { createRedux, bindActionCreators } from 'redux'; // Import components and decorators from redux/react import { provide, Connector } from 'redux/react'; // React Native: Import components and decorators from redux/react-native import { provide, Connector } from 'redux/react-native';0.10 release also had a problem with ES6 code inside
redux/reactandredux/react-nativeentry points, which is now fixed. Please upgrade if you had problems with 0.10.Changes introduced in 0.10.1:
Connectornow throws ifselectreturns something other than a plain object (#85)The custom dispatcher API is tweaked so
setStatenow returns the state that was actually set. This makes custom dispatchers more composable. (#77)
Happy reducing!
0.10.0
13 Jun 2015Redux 1.0 is within striking distance! Can you believe how quickly Redux has matured? @gaearon made the first commit only 14 days ago.
Middleware
Redux 1.0 is within striking distance! Can you believe how quickly Redux has matured? @gaearon made the first commit only 14 days ago.
The 0.10 release is a follow-up to 0.9, with a focus on what we're calling (at least for now) middleware.
You can read all about middleware here. We plan to release some official middleware soon, but of course we'd also love to see middleware created by the community.
Breaking changes
Just a small one: Redux includes a feature that enables you to return a function from an action creator to perform asynchronous dispatches. The function receives a callback and
getState()as parameters. This has behavior has been re-implemented as middleware and moved into a separate module calledthunkMiddleware(). It is included automatically when using thecreateRedux(stores)shortcut, but not when usingcreateDispatcher().Tests
We have tests! Still need to improve coverage in a few areas, but we're currently at ~93%. Not bad! Big thanks to @emmenko for setting these up.
- 0.9.x
0.9.0
9 Jun 2015createDispatchernow returns a function you need to give tocreateReduxcreateReduxis the primary API you'll use for initializationInstead of
dispatcherprop, adispatchfunction prop is injected by the<Connector>and@connect
Internal Refactoring & Custom Dispatchers
This release brings breaking changes necessary to start experimenting with middleware and extensibility (#6, #55). It does not bring any support for middleware per se, but it untangles “Dispatcher” (a function that tells how actions turn into state updates) from “Redux” (an instance holding the current state and managing subscriptions). It is now possible to specify your own Dispatcher if you want to experiment with ideas like middleware, time travel, action creators returning Promises or Observables, etc.
createDispatchernow returns a function you need to give tocreateReduxcreateReduxis the primary API you'll use for initializationInstead of
dispatcherprop, adispatchfunction prop is injected by the<Connector>and@connectInstead of
dispatcherprop,<Provider>and@provideaccept areduxpropInstead of
dispatcher.getAtom(), useredux.getState()Instead of
dispatcher.setAtom(), you may pass a secondinitialStateargument tocreateReduxInstead of
dispatcher.perfrorm()ordispatcher.dispatch(), useredux.dispatch()bindActionsis renamed tobindActionCreatorsand acceptsdispatchas the second parameterYou may skip
composeStoresandcreateDispatchercompletely and just usecreateRedux(stores)as a shortcut
How It Looks Like Now
Initialization
Short Way
This is a shortcut for the most common use case.
import { createRedux, Provider } from 'redux'; import * as stores from '../stores/index'; const redux = createRedux(stores); export default class App { render() { return ( <Provider redux={redux}> {() => <CounterApp /> } </Provider> ); } }Long Way
This way of writing lets you use compose Stores differently, or even pass a custom Dispatcher function. Its signature is
(initialState, setState) => (action) => ().import { createRedux, createDispatcher, composeStores } from 'redux'; import * as stores from '../stores/index'; // Compose all your Stores into a single Store function with `composeStores`: const store = composeStores(stores); // Create a default Dispatcher function for your composite Store: const dispatcher = createDispatcher(store); // You may use your custom function here // Create a Redux instance using the dispatcher function: const redux = createRedux(dispatcher); export default class App { render() { return ( <Provider redux={redux}> {() => <CounterApp /> } </Provider> ); } }Hydration and dehydration
// server const redux = createRedux(stores); redux.dispatch(MyActionCreators.doSomething()); // fire action creators to fill the state const state = redux.getState(); // somehow pass this state to the client // client const initialState = window.STATE_FROM_SERVER; const redux = createRedux(stores, initialState);
Binding actions
import React from 'react'; import { connect, bindActionCreators } from 'redux'; import Counter from '../components/Counter'; import * as CounterActions from '../actions/CounterActions'; @connect(state => ({ counter: state.counter })) export default class CounterApp { render() { const { counter, dispatch } = this.props; return ( <Counter counter={counter} {...bindActionCreators(CounterActions, dispatch)} /> ); } }- 0.8.x
0.8.1
6 Jun 2015hydrate()anddehydrate()are gone, welcomegetAtom()andsetAtom()insteadinitialize()anddispose()are added for advanced use casesChanging
selectfunction now updates theConnectorstate
hydrate()anddehydrate()are gone, welcomegetAtom()andsetAtom()insteadinitialize()anddispose()are added for advanced use casesChanging
selectfunction now updates theConnectorstateThe bug with action creators accepting
dispatchinstead ofperformis fixed