@gaearon gaearon released this Aug 7, 2015 · 595 commits to master since this release

Assets 2

New API!

As discussed in #1 and implemented by @gnoff in #16, we wanted to make connect() more powerful. Now it supports binding action creators! However, it stays performant. In fact, you can write more performant Redux apps with it because new connect() takes care of only binding action creators once.

Breaking Changes

There is just one breaking change: the function passed to connect no longer accepts props as a second argument. The upgrade path is to specify mergeProps function as the third argument in connect:

Before

connect((state, props) => state.todosByUser[props.userId])

After

connect(
  (state) => ({ todos: state.todos }),
  null,
  (stateSlice, actionCreators, props) => ({
    todos: stateSlice.todosByUser[props.userId]
  })

The upside is you can now add action creators depending on props just as easily:

connect(
  (state) => ({ todos: state.todos }),
  TodoActionCreators,
  (stateSlice, actionCreators, props) => ({
    todos: stateSlice.todosByUser[props.userId],
    addTodo: (text) => actionCreators.addTodo(props.userId, text)
  })

Improvements

Here's what you can do with the new connect()!

Inject just dispatch and don't listen to store
export default connect()(TodoApp);
Inject dispatch and every field in the global state (SLOW!)
export default connect(state => state)(TodoApp);
Inject dispatch and todos
function mapState(state) {
  return { todos: state.todos };
}

export default connect(mapState)(TodoApp);
Inject todos and all action creators (addTodo, completeTodo, ...)
import * as actionCreators from './actionCreators';

function mapState(state) {
  return { todos: state.todos };
}

export default connect(mapState, actionCreators)(TodoApp);
Inject todos and all action creators (addTodo, completeTodo, ...) as actions
import * as actionCreators from './actionCreators';
import { bindActionCreators } from 'redux';

function mapState(state) {
  return { todos: state.todos };
}

function mapDispatch(dispatch) {
  return { actions: bindActionCreators(actionCreators, dispatch) };
}

export default connect(mapState, mapDispatch)(TodoApp);
Inject todos and a specific action creator (addTodo)
import { addTodo } from './actionCreators';
import { bindActionCreators } from 'redux';

function mapState(state) {
  return { todos: state.todos };
}

function mapDispatch(dispatch) {
  return bindActionCreators({ addTodo }, dispatch);
}

export default connect(mapState, mapDispatch)(TodoApp);
Inject todos, todoActionCreators as todoActions, and counterActionCreators as counterActions
import * as todoActionCreators from './todoActionCreators';
import * as counterActionCreators from './counterActionCreators';
import { bindActionCreators } from 'redux';

function mapState(state) {
  return { todos: state.todos };
}

function mapDispatch(dispatch) {
  return {
    todoActions: bindActionCreators(todoActionCreators, dispatch),
    counterActions: bindActionCreators(counterActionCreators, dispatch)
  };
}

export default connect(mapState, mapDispatch)(TodoApp);
Inject todos, and todoActionCreators and counterActionCreators together as actions
import * as todoActionCreators from './todoActionCreators';
import * as counterActionCreators from './counterActionCreators';
import { bindActionCreators } from 'redux';

function mapState(state) {
  return { todos: state.todos };
}

function mapDispatch(dispatch) {
  return {
    actions: bindActionCreators({ ...todoActionCreators, ...counterActionCreators }, dispatch)
  };
}

export default connect(mapState, mapDispatch)(TodoApp);
Inject todos, and all todoActionCreators and counterActionCreators directly as props
import * as todoActionCreators from './todoActionCreators';
import * as counterActionCreators from './counterActionCreators';
import { bindActionCreators } from 'redux';

function mapState(state) {
  return { todos: state.todos };
}

function mapDispatch(dispatch) {
  return bindActionCreators(Object.assign({}, todoActionCreators, counterActionCreators), dispatch);
}

export default connect(mapState, mapDispatch)(TodoApp);
Inject todos of a specific user depending on props, and inject props.userId into the action
import * as actionCreators from './actionCreators';

function mapState(state) {
  return { todos: state.todos };
}

function mergeProps(state, actions, props) {
  return Object.assign({}, props, {
    todos: state.todos[props.userId],
    addTodo: (text) => actions.addTodo(props.userId, text)
  });
}

export default connect(mapState, actionCreators, mergeProps)(TodoApp);