Releases: reduxjs/redux
v3.0.2
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, reduxjs/redux-devtools#106, reduxjs/redux-devtools#120)
To enjoy this, you’ll need at least [email protected].
v3.0.1
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, reduxjs/redux-devtools#106, reduxjs/redux-devtools#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!
v3.0.0
v2.0.0
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 add module.hot API 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.js instead of creating a separate <Root> component. See #667 for a migration example.
compose() now acts like a proper compose() (#669)
This fixes the embarrassing mishap that compose() API was.
As suggested by @jlongster, now it is a proper compose() 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 createStore from 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_ENV is 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_ENV polyfill, 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.
v1.0.1
v1.0.0
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:
- 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 https://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: #352- Dispatching 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:
v1.0.0-rc
NOTE: THIS IS A PRE-RELEASE WITH SOME BREAKING CHANGES.
THE README IS NOT UPDATED TO ITS API, SEE EXAMPLES AND TESTS INSTEAD.
Compatible example code: https://github.com/gaearon/redux/tree/v1.0.0-rc/examples
Compatible test code: https://github.com/gaearon/redux/tree/v1.0.0-rc/test
Changes in these release build on top of changes in 1.0 alpha release, so check them out first.
Big Changes
React-specific code has been moved to react-redux and will be versioned separately
This means that <Provider>, @provide, <Connector>, @connect are all there. This means you need to replace 'redux/react' with react-redux and redux/react-native with react-redux/native in your dependency tree, as well as add react-redux as an explicit dependency if you use React. For global builds, you'll get Redux from this library and ReactRedux from the other library. They should work together well.
Link: #230
1.0 alpha
import { createStore } from 'redux';
import { Provider } from 'redux/react'; // React
import { Provider } from 'redux/react-native'; // React Native1.0 RC
import { createStore } from 'redux';
import { Provider } from 'react-redux'; // React
import { Provider } from 'react-redux/native'; // React NativecreateStore no longer implicitly combines reducers
Now you have to use combineReducers explicitly to combine several reducer functions into a single reducer.
Link: #257
1.0 alpha
import { createStore } from 'redux';
import * as reducers from '../reducers';
const store = createStore(reducers);1.0 RC
import { createStore, combineReducers } from 'redux';
import * as reducers from '../reducers';
const reducer = combineReducers(reducers)
const store = createStore(reducer);All middleware is now “smart” middleware
All middleware now accepts { getState, dispatch } as the first parameter. This means that, if your middleware already accepted ({ dispatch, getState }), you don't need to change anything, but otherwise you need to wrap your middleware into one more function.
Link: #213
1.0 alpha
// “Dumb” middleware
export function log(next) {
return (action) => {
console.log(action);
return next(action);
};
}
// “Smart” middleware
export function thunk({ dispatch, getState }) {
return next => action =>
typeof action === 'function' ?
action(dispatch, getState) :
next(action);
}1.0 RC
// “Dumb” middleware is wrapped in one more function
export function log(/* { dispatch, getState } */) {
return next => action => {
console.log(action);
return next(action);
};
}
// “Smart” middleware stays the same
export function thunk({ dispatch, getState }) {
return (next) => (action) =>
typeof action === 'function' ?
action(dispatch, getState) :
next(action);
}createStore no longer accepts middleware
You need to use a dedicated applyMiddleware(...middlewares) function that turns a vanilla createStore into a middleware-capable createStore.
Link: #213
1.0 alpha
import { createStore } from 'redux';
import * as reducers from '../reducers';
const store = createStore(
reducers,
initialState,
({ getState, dispatch }) => [thunk({ getState, dispatch }), logger]
);1.0 RC
import { createStore, combineReducers, applyMiddleware } from 'redux';
import * as reducers from '../reducers';
const reducer = combineReducers(reducers);
const finalCreateStore = applyMiddleware(thunk, logger)(createStore);
const store = finalCreateStore(reducer, initialState);The thunk middleware is no longer included by default
If you use “async action creator” form where an action creator returns a function with dispatch, getState => ... signature, now you need to add redux-thunk as a dependency and explicitly pass it to applyMiddleware.
Link: #256
1.0 alpha
import { createStore } from 'redux';
import * as reducers from '../reducers';
const store = createStore(reducers, initialState);
store.dispatch(incrementAsync());1.0 RC
import { createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import * as reducers from '../reducers';
const reducer = combineReducers(reducers);
const finalCreateStore = applyMiddleware(thunk)(createStore);
const store = finalCreateStore(reducer, initialState);
store.dispatch(incrementAsync());Correctness Changes
combineReducers now throws if you return undefined state
Previously, reducers could return undefined as a valid value. Unfortunately it's too easy to do this by mistake by putting an early return into a reducer, or by forgetting to specify a default case inside the switch statement. The new behavior is to throw in combineReducers if you return undefined while handling an action or initializing. If undefined is a valid state for your reducer, consider using null instead.
1.0 alpha
function toggle(state, action) {
switch (action.type) {
case SET_ON:
return true;
case SET_OFF:
return undefined;
}
}1.0 RC
function toggle(state = false, action) {
switch (action.type) {
case SET_ON:
return true;
case SET_OFF:
return false;
default:
return state;
}
}combineReducers throws if you have no default case
Handling @@INIT action is an anti-pattern. It's internal to Redux, and you should never handle it directly. It is renamed to @@redux/INIT in Redux 1.0 RC. In addition, Redux now throws if your reducer does not return an initial state in response to a randomized action type.
If you used @@INIT action to return the initial state, you should instead return it when the state passed as the first argument is undefined, regardless of the action type. You should remove any reference to @@INIT action type from your code.
If you used @@INIT action to transform rehydrated state from server (for example, to turn plain objects into immutable maps), you need to do this by inspecting state instead. For example, see how redux-example fixed this problem.
1.0 alpha
function counter(state, action) {
switch (action.type) {
case '@@INIT': // You could get away with this in alpha
return 0;
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
}
}
function immutable(state = Immutable.fromJS({}), action) {
switch (action.type) {
case '@@INIT': // You could get away with this in alpha
return Immutable.fromJS(state);
case DO_SOMETHING:
return state.merge(something);
}
}1.0 RC
function counter(state = 0, action) {
switch (action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
default:
return state; // Will be probed by a random action
}
}
function immutable(state = {}, action) {
if (!Map.isMap(state) && !List.isList(state)) {
state = Immutable.fromJS(state);
}
switch (action.type) {
case DO_SOMETHING:
return state.merge(something);
default:
return state; // Will be probed by a random action
}
}(React) Components now update correctly in response to the actions fired in componentDidMount
Link: #208
Dispatch from the middleware sends the dispatch through the whole middleware chain
Link: #250
v1.0.0-alpha
NOTE: THIS IS A PRE-RELEASE WITH SOME BREAKING CHANGES.
THE README IS NOT UPDATED TO ITS API, SEE EXAMPLES AND TESTS INSTEAD.
Compatible example code: https://github.com/gaearon/redux/tree/v1.0.0-alpha/examples
Compatible test code: https://github.com/gaearon/redux/tree/v1.0.0-alpha/test
Full diff (includes changes to the examples, tests and implementation):
https://github.com/rackt/redux/compare/v0.12.0...v1.0.0-alpha?diff=unified
Naming
- “Stateless Stores” are now called reducers. (#137 (comment))
- The “Redux instance” is now called “The Store”. (#137 (comment))
- The dispatcher is removed completely. (#166 (comment))
API changes
is nowcomposeStorescomposeReducers.is gone.createDispatcheris nowcreateReduxcreateStore.<Provider>now acceptsstoreprop instead of.redux- The new
createStoresignature iscreateStore(reducer: Function | Object, initialState: any, middlewares: Array | ({ getState, dispatch }) => Array). - If the first argument to
createStoreis an object,composeReducersis automatically applied to it. - The “smart” middleware signature changed. It now accepts an object instead of a single
getStatefunction. Thedispatchfunction lets you “recurse” the middleware chain and is useful for async: #113 (comment).
Correctness changes
- The
dispatchprovided by the default thunk middleware now walks the whole middleware chain. - It is enforced now that raw Actions at the end of the middleware chain have to be plain objects.
- Nested dispatches are now handled gracefully. (#110, #119)
Internal changes
- The object in React context is renamed from
toreduxstore. - Some tests are rewritten for clarity, focus and edge cases.
- Redux in examples is now aliased to the source code for easier work on master.
v0.12.0
No breaking changes this time.
- Classes returned by decorators now expose a static
DecoratedComponentproperty for easier testing - Dependencies on
lodashandbabel-runtimeare dropped - Now 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)

