在redux docs我看到了:
常见错误#1:指向相同对象的新变量
定义新变量不会创建新的实际对象 - 它只会创建对同一对象的另一个引用。这个错误的一个例子是:
function updateNestedState(state, action) {
let nestedState = state.nestedState;
// ERROR: this directly modifies the existing object reference - don't do this!
nestedState.nestedField = action.data;
return {
...state,
nestedState
};
}
此函数正确返回顶级状态对象的浅表副本,但由于
nestedState
变量仍指向现有对象,因此状态直接发生变异。
但是我们知道combineReducers
只是通过顶级参考判断状态变化。参见redux comBindReducer.js src:
let hasChanged = false
const nextState = {}
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i]
const reducer = finalReducers[key]
const previousStateForKey = state[key]
const nextStateForKey = reducer(previousStateForKey, action)
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
它只访问每个reducer并判断状态引用是否发生了变化。
回到这个问题,修改了对象引用,因此hasChanged
变量为true,而redux工作正常。所以我不知道状态的副作用是直接的?
如果你知道,请告诉我,谢谢。
答案 0 :(得分:3)
我不认为该示例与cobmineReducers
直接相关。我相信它试图提出与不变性相关的警告:每当复杂对象内的值发生变化时,整个层次结构都应该表明这一点。因此,如果state.nestedState.nestedField
发生变化,则表示state.nestedState
已发生变化,state
也发生变化。只需查看state
或nestedState
就可以了解nestedField
已发生变化。
对这个概念不熟悉的开发人员可能经常认为将state.nestedState
分配给新变量然后更改它很好,但事实并非如此,因为a === state.nestedState
仍然是{ {1}}。
true
只关心其中一个切片是否已更改。如果遵循上面的规则,它将会正常工作&#34;。但是,如果我们直接关注combineReducers
会发生什么?参考文献仍然相同,因此不再适用。
说到React,connect
以同样的方式工作。浅析比较道具,依赖于相同的规则:不需要深入比较,因为父母应该指出孩子是否已经改变。
回到你的问题:直接改变国家有什么副作用?
让我们使用你的例子:
state.nestedState
这样可以正常工作:
// reducer.js
function reducer(state, action) {
let nestedState = state.nestedState;
nestedState.nestedField = action.data;
return {
...state,
nestedState
};
}
这不会:
connect(state => ({ state }))(MyComponent)
我希望它能回答你的问题,或者至少对它有所了解。