laurent
laurent

Reputation: 90804

What could happen if modifying state directly inside a Redux reducer?

I'm looking at this Redux tutorial where the following reducer is being discussed:

function visibilityFilter(state = 'SHOW_ALL', action) {
    return action.type === 'SET_VISIBILITY_FILTER' ?
        action.filter :
        state
}

function todos(state = [], action) {
    switch (action.type) {
        case 'ADD_TODO':
            return state.concat([{
                text: action.text, completed: false
            }]);
        case 'TOGGLE_TODO':
            return state.map((todo, index) =>
                action.index === index ?
                    { text: todo.text, completed: !todo.completed } :
                    todo
            )
        default: return state;
    }
}

function todoApp(state = {}, action) {
    return {
        todos: todos(state.todos, action),
        visibilityFilter: visibilityFilter(state.visibilityFilter, action)
    };
}

What it does it clear, however I don't get why it does the state.concat / state.map to duplicate the state instead of working on it directly. I understand it's to achieve immutability, but, technically, what could go wrong if I change the code from this:

return state.map((todo, index) =>
    action.index === index ?
        { text: todo.text, completed: !todo.completed } :
        todo
)

to this:

state[action.index].completed = !state[action.index].completed;
return state;

The state that was passed to the reducer is obsolete anyway, so whether it has been changed or not it must not be used anywhere (and if I'm not mistaken that's indeed what Redux is doing - it ignores the previous state and takes the new one as the "source of truth"). So only the new state returned by the function should matter.

So if I follow this approach of modifying the state directly in the reducer and returning this, what bug could that create in my application? Any idea?

Upvotes: 8

Views: 3027

Answers (3)

markerikson
markerikson

Reputation: 67539

The core of Redux does not care about immutability. It also does not actually do anything to prevent mutations, either inside reducers or in other partso f your application. However, mutations will break time-travel debugging, as well as the React-Redux connect function. There's a new section of the Redux FAQ on Immutable Data that describes in more detail how and why Redux relies on immutability, and the question on Why isn't my component re-rendering? also applies.

Also, I'm currently working on a blog post that will discuss what technical limitations Redux actually requires, vs how you are intended to use Redux, vs how it's possible to use Redux. I'm hoping to have that post up within the next week. If you're interested, keep an eye on my blog at http://blog.isquaredsoftware.com.

Upvotes: 4

Andy Ray
Andy Ray

Reputation: 32076

Redux compares your old state to your new state with === to know if it changed. If you mutate the state instead of creating a new copy, this test will fail and your components won't update.

Upvotes: 14

Konstantinos Leimonis
Konstantinos Leimonis

Reputation: 1027

Working with redux and the action-reducers pattern is all about pure functions. Reducers should be pure functions, which means that they should not mutate the state. Pure functions take an input and return a new output. In case redux didn't use this pattern and the state was mutated then the data would be unreliable and as result cause bugs in your application for example your react components would not get updated.

Upvotes: 0

Related Questions