我正处于React + Redux游戏的早期开发阶段,并遵循Redux最佳实践:纯缩减器,表示/容器组件分离,仅在Reducer中使用getState()
(与动作创建者相对)等该应用程序似乎按预期工作,但当我尝试使用Time Travel撤消操作时,即使状态属性map[][]
及其计算的连接组件道具按预期更改,结果也不会如此正确地反映在UI上(具体地说,地图上的玩家位置不遵循状态指示)。当我检查状态变化时,我可以看到所有必要的变化都在不同状态之间正确发生。这是我的减速机:
const gridReducer = (state, action) => {
if (typeof state === 'undefined'){
let dungeon = new Dungeon();
dungeon.generate();
return {
boardWidth: Math.floor(((70/100) * window.innerWidth) / 20),
boardHeight: Math.floor(((70/100) * window.innerHeight) / 20),
map: dungeon.map,
position: dungeon.playerPosition
}
}
switch (action.type) {
case 'GRID_RESIZE':
return {...state,
boardWidth: action.newBoardWidth,
boardHeight: action.newBoardHeight
}
//This is where I have the issue, map correctly changes both when interacting with the game and when reversing using time travel however the UI fails to update (only in reverse)!
case 'MOVE':
let dungeonObj = new Dungeon(state.map.slice(), {...state.position});
if (dungeonObj.movePlayer(action.direction)) {
return {...state,
position: dungeonObj.playerPosition,
map: dungeonObj.map
}
} else return state;
default:
return state;
}
}
如果你想看一下,这是完整的代码!该应用程序目前仅支持通过按箭头键移动地牢中的玩家,并且该视图应始终基于玩家的位置为中心(玩家在使用时间旅行时无法返回) http://s.codepen.io/sabahang/debug/GjrPNQ
PS:Dungeon.generate确实使用了Math.Random,但我只在initialState
中使用此功能,并且对于已发送的操作,我只是通过发送生成的地图来生成浅层副本当前状态到Dungeon构造函数并使用其他方法(例如movePlayer)
答案 0 :(得分:1)
找到了罪魁祸首。它根本不是Redux的错,它与React的工作方式有关!如果你是React的新手,你还没有陷入这个陷阱,还在等待它!
这与以下事实有关:Redux中实现纯粹的Reducer所需的大多数复制深层嵌套对象的传统方法实际上是对象和属性的浅层复制。内存引用仍然指向原始状态。 React基于旧状态和新状态的深度比较来更新UI,并且当一些引用相同时,它无法正确地更新UI。这里我有一个二维数组map[][]
,它是一个对象,虽然我使用ES6扩展运算符来避免因为正在制作卷影副本而修改原始状态,但是原始{{1}的深层嵌套索引正在被修改。一种解决方案是使用`Array.map()'创建一个全新的对象,但我最终使用immutablejs,它修复了我的问题与时间旅行滑块。
如果您不想花费数周时间在复杂的应用中追逐类似的错误,这是一个强烈推荐的参考:http://redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html
根据您的具体需求,有大量的不变性帮助者可以提供帮助: https://github.com/markerikson/redux-ecosystem-links/blob/master/immutable-data.md#immutable-update-utilities
这个也只对Redux有趣: https://github.com/indexiatech/redux-immutablejs
此问题可能与以下内容重复: React-redux store updates but React does not