如果直接在 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。
我正在查看这个 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。