Troubleshooting

    Sometimes, you are trying to dispatch an action, but your view does not update. Why does this happen? There may be several reasons for this.

    Never mutate reducer arguments

    It is tempting to modify the or action passed to you by Redux. Don't do this!

    Redux assumes that you never mutate the objects it gives to you in the reducer. Every single time, you must return the new state object. Even if you don't use a library like Immutable, you need to completely avoid mutation.

    Immutability is what lets efficiently subscribe to fine-grained updates of your state. It also enables great developer experience features such as time travel with redux-devtools.

    For example, a reducer like this is wrong because it mutates the state:

    It needs to be rewritten like this:

    1. function todos(state = [], action) {
    2. switch (action.type) {
    3. case 'ADD_TODO':
    4. // Return a new array
    5. return [
    6. ...state,
    7. {
    8. text: action.text,
    9. completed: false
    10. }
    11. ]
    12. case 'COMPLETE_TODO':
    13. // Return a new array
    14. return state.map((todo, index) => {
    15. if (index === action.index) {
    16. // Copy the object before mutating
    17. return Object.assign({}, todo, {
    18. completed: true
    19. }
    20. return todo
    21. })
    22. default:
    23. return state
    24. }
    25. }

    Finally, to update objects, you'll need something like from Underscore, or better, an polyfill.

    Make sure that you use Object.assign correctly. For example, instead of returning something like Object.assign(state, newData) from your reducers, return Object.assign({}, state, newData). This way you don't override the previous state.

    You can also enable the object spread operator proposal for a more succinct syntax:

    1. // Before:
    2. return state.map((todo, index) => {
    3. if (index === action.index) {
    4. return Object.assign({}, todo, {
    5. completed: true
    6. })
    7. }
    8. return todo
    9. })
    10. // After:
    11. return state.map((todo, index) => {
    12. if (index === action.index) {
    13. return { ...todo, completed: true }
    14. }
    15. return todo
    16. })

    Note that experimental language features are subject to change.

    Also keep an eye out for nested state objects that need to be deeply copied. Both _.extend and Object.assign make a shallow copy of the state. See for suggestions on how to deal with nested state objects.

    Don't forget to call dispatch(action)

    If you define an action creator, calling it will not automatically dispatch the action. For example, this code will do nothing:

    TodoActions.js

    AddTodo.js

    1. import React, { Component } from 'react'
    2. import { addTodo } from './TodoActions'
    3. class AddTodo extends Component {
    4. // Won't work!
    5. addTodo('Fix the issue')
    6. }
    7. render() {
    8. return <button onClick={() => this.handleClick()}>Add</button>
    9. }
    10. }

    The fix is to call method on the store instance:

    If you're somewhere deep in the component hierarchy, it is cumbersome to pass the store down manually. This is why lets you use a connect higher-order component that will, apart from subscribing you to a Redux store, inject dispatch into your component's props.

    The fixed code looks like this:

    AddTodo.js

    1. import React, { Component } from 'react'
    2. import { connect } from 'react-redux'
    3. import { addTodo } from './TodoActions'
    4. class AddTodo extends Component {
    5. handleClick() {
    6. // Works!
    7. this.props.dispatch(addTodo('Fix the issue'))
    8. }
    9. render() {
    10. return <button onClick={() => this.handleClick()}>Add</button>
    11. }
    12. }
    13. // In addition to the state, `connect` puts `dispatch` in our props.

    You can then pass down to other components manually, if you want to.

    Make sure mapStateToProps is correct

    It's possible you're correctly dispatching an action and applying your reducer but the corresponding state is not being correctly translated into props.

    Ask around on the #redux Discord channel, or create an issue.If you figure it out, as a courtesy to the next person having the same problem.