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

Posted

技术标签:

【中文标题】如果直接在 Redux reducer 中修改状态会发生啥?【英文标题】:What could happen if modifying state directly inside a Redux reducer?如果直接在 Redux reducer 中修改状态会发生什么? 【发布时间】:2017-10-01 05:28:36 【问题描述】:

我正在查看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 正在做的事情 - 它忽略了之前的状态并将新的作为“真相的来源”)。所以只有函数返回的新状态才重要。

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

【问题讨论】:

这个答案详细解释http://***.com/questions/35970515/how-is-state-immutability-actually-used-in-redux 【参考方案1】:

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

【讨论】:

谢谢,我认为这是关键,Redux 比较通过 reducer 发送前后状态的方式。如果是进行深度比较,我们就不需要关心这个了。我觉得这实际上有点抽象,但出于性能原因,这是必要的。 我不认为这是一个泄漏的抽象。不可变编程是一种众所周知的范式,并且在 JS 社区中获得了更多的关注。 我对此并不完全确定。这里(以及其他地方,以及我读过的任何内容)都没有人可以解释如果状态改变会引入什么错误,然后从减速器内部返回。好的,原因是 Redux 正在做的 ===,这是一种优化。但是,如果它进行深度比较,那么不变性就没有意义了。话虽如此,也许我错过了什么。 我还要说,直接更新状态会使反向重播应用程序变得困难,并且在分派给定操作之前清楚地看到状态是什么。我的假设也正确吗?【参考方案2】:

Redux 的核心并不关心不变性。它实际上也没有做任何事情来防止突变,无论是在减速器内部还是在应用程序的其他部分。然而,突变会破坏时间旅行调试,以及 React-Redux connect 函数。 Immutable Data 上的 Redux 常见问题解答中有一个新部分更详细地描述了 Redux 如何以及为什么依赖于不变性,Why isn't my component re-rendering? 上的问题也适用。

另外,我目前正在撰写一篇博文,讨论 Redux 实际需要哪些技术限制,以及您打算如何使用 Redux,以及它如何可能 使用 Redux。我希望在下周内发布该帖子。如果您有兴趣,请关注我的博客http://blog.isquaredsoftware.com。

【讨论】:

【参考方案3】:

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

【讨论】:

如果我们知道我们在做什么。这应该不是问题。一个例子是当我们想将 redux 用作全局存储时。想象一棵树,它可以长到任何大小。每次完全复制它都会对性能造成很大影响,我们可以对其进行变异。而且我们从不直接使用它来更新我们的组件。我们通过强制重新渲染来触发更新时的重新渲染。为此类极端情况提供此类功能。评论将有助于澄清事情。

以上是关于如果直接在 Redux reducer 中修改状态会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

Redux

Redux学习笔记

在 Redux Reducer 中读取 Store 的初始状态

Redux Toolkit:状态在 reducer 中显示为 Proxy / undefined

自己简写一个redux(redux源码简写)

我如何在 react redux 中访问另一个 reducer 的状态。 reducer 和 store 之间的状态流