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 Native
1.0 RC
import { createStore } from 'redux';
import { Provider } from 'react-redux'; // React
import { Provider } from 'react-redux/native'; // React Native
createStore
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