如果直接在 Redux reducer 中修改状态会发生什么?

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

我正在查看这个 Redux tutorial,其中正在讨论以下减速器:

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)
    };
}

它清楚地说明了什么,但是我不明白 为什么 它执行 state.concat / state.map 来复制状态而不是继续工作它直接。我知道这是为了实现不变性,但是,从技术上讲,如果我从这里更改代码,可能会出什么问题:

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

对此:

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

传递给 reducer 的状态无论如何都是过时的,所以不管它是否被改变,它都不能在任何地方使用(如果我没记错的话,这确实是 Redux 正在做的 - 它忽略了之前的state 并将新的作为 "source of truth")。所以只有函数返回的新状态才是重要的。

因此,如果我按照这种直接在 reducer 中修改状态并返回它的方法,那会在我的应用程序中产生什么错误?有什么想法吗?

使用 redux 和 action-reducers 模式都是关于纯函数的。 Reducers 应该是纯函数,这意味着它们不应该改变状态。纯函数接受一个输入,return 一个新的输出。如果 redux 没有使用这种模式并且状态发生了变化,那么数据将不可靠,结果会导致您的应用程序出现错误,例如您的反应组件将无法更新。

Redux 使用 === 将您的旧状态与新状态进行比较,以了解它是否发生了变化。如果您改变状态而不是创建新副本,则此测试将失败并且您的组件将不会更新。

Redux 的核心不关心不变性。它实际上也没有做任何事情来防止突变,无论是在 reducer 内部还是在应用程序的其他部分。然而,突变会破坏时间旅行调试,以及 React-Redux connect 功能。 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? 上的 Redux 常见问题解答的新部分也适用。

此外,我目前正在写一个博客 post,该博客将讨论 Redux 实际需要哪些技术限制,以及您打算 使用 Redux 的方式,以及如何可能 使用 Redux。我希望在下周内完成 post。如果您有兴趣,请关注我的博客 http://blog.isquaredsoftware.com