Skip to content

Releases: reduxjs/redux

v3.0.2

26 Sep 09:02
Compare
Choose a tag to compare

One of the problems v3.0.1 was intended to solve was not completely fixed in 3.0.1.
This release amends that.

To enjoy this, you’ll need at least redux-devtools@2.1.4.

v3.0.1

25 Sep 22:26
Compare
Choose a tag to compare

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 from combineReducers() 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 from combineReducers() isn't a very common pattern. (#715, #720)
  • The reducer probing performed by combineReducers() as a sanity check has been moved from the combineReducers() call to the first reducer invocation. Technically the check is still performed during the combineReducers() call, but the error is only thrown after during the initial dispatch. (Usually that would correspond to the createStore()call.) This reason for this is that otherwise an error thrown inside a reducer used to blow up combineReducers() 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 in combineReducers() 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

12 Sep 23:49
Compare
Choose a tag to compare

Breaking Changes

  • Action objects now must have a type property other than undefined (#541, #564)

Other Changes

  • replaceReducer() is un-deprecated.

v2.0.0

01 Sep 01:25
Compare
Choose a tag to compare

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

15 Aug 10:21
Compare
Choose a tag to compare
  • Fixes “process is not defined” on React Native (#525, #526)
  • Removes dependencies on invariant and warning (#528)
  • Fixes TodoMVC example (#524, #529)

v1.0.0

14 Aug 16:11
Compare
Choose a tag to compare

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 dispatch is 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
  • bindActionCreators now 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

13 Jul 18:32
Compare
Choose a tag to compare

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.

Links: #173, #191, #193, #197, #259

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.

Links: #186, #259

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

30 Jun 21:58
Compare
Choose a tag to compare
v1.0.0-alpha Pre-release
Pre-release

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

API changes

  • composeStores is now composeReducers.
  • createDispatcher is gone.
  • createRedux is now createStore.
  • <Provider> now accepts store prop instead of redux.
  • The new createStore signature is createStore(reducer: Function | Object, initialState: any, middlewares: Array | ({ getState, dispatch }) => Array).
  • If the first argument to createStore is an object, composeReducers is automatically applied to it.
  • The “smart” middleware signature changed. It now accepts an object instead of a single getState function. The dispatch function lets you “recurse” the middleware chain and is useful for async: #113 (comment).

Correctness changes

  • The dispatch provided 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 redux to store.
  • 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

19 Jun 00:35
Compare
Choose a tag to compare
v0.12.0 Pre-release
Pre-release

No breaking changes this time.

  • Classes returned by decorators now expose a static DecoratedComponent property for easier testing
  • Dependencies on lodash and babel-runtime are dropped
  • Now compatible with Babel loose mode
  • composeStore now 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 @@INIT type (might be useful to devtools)

v0.11.1

16 Jun 15:24
Compare
Choose a tag to compare
v0.11.1 Pre-release
Pre-release
  • Bugfix: when Connector select property changes, the state did not recalculate (#107)