【问题标题】:Does JSON.parse(JSON.stringify(state)) guarantee no mutation of redux state?JSON.parse(JSON.stringify(state)) 是否保证 redux 状态没有突变?
【发布时间】:2017-10-04 18:06:04
【问题描述】:

我一直在追踪一个问题,即 redux 存储正确更新,但组件未反映更改。我尝试了多种方法来确保我没有改变状态,但是问题仍然存在。我的减速器通常采用以下形式:

case 'ADD_OBJECT_TO_OBJECT_OF_OBJECTS': {
    newState = copyState(state);
    newState.objectOfObjects[action.id] = action.obj;
    return newState;
}

对于我的 copyState 函数,我通常使用嵌套的 Object.assign() 调用,但避免错误并不是那么简单。为了测试,为了确保我没有改变状态,使用是否正确

const copyState = (state) => {
    return JSON.parse(JSON.stringify(state));
};

作为一种保证不改变(redux)状态的方法,不管这个过程有多昂贵?

如果没有,我可以依靠其他任何深拷贝方法来确保我不会改变状态吗?

编辑: 考虑到其他人可能会遇到同样的问题,我会将解决方案转达给我遇到的问题。

我试图调度一个动作,然后在之后的一行中,我试图从上一行更新的存储中访问数据。

dispatchAction(data) // let's say this updates a part of the redux state called 'collection'
console.log(this.props.collection) // This will not be updated!

参考https://github.com/reactjs/redux/issues/1543

【问题讨论】:

  • statecopyState 中将保持不变
  • state 一个改变它的.toJSON 方法是可能的(但非常愚蠢)。

标签: javascript json reactjs redux state


【解决方案1】:

是的,这可以进行深度克隆,无论它多么昂贵。困难(正如问题下的评论所暗示的)是确保state 在其他任何地方都保持不变。

由于您要求其他方法,而这不适合评论,我建议查看ImmutableJS,它消除了跟踪状态突变错误的问题(但可能有其自身的限制) :

const { Map } = require('immutable')
const map1 = Map({ a: 1, b: 2, c: 3 })
const map2 = map1.set('b', 50)
map1.get('b') // 2
map2.get('b') // 50

【讨论】:

  • 感谢您的回答。但是我想确保我对 redux 没有根本的误解。你提到'确保其他地方的国家保持不变'。为了进行测试,我在每个 reducer 中都使用了这种 JSON.parse() 方法。尽管如此,商店仍然正确更新(中间件在动作调度后显示“nextState”中的更改)但组件没有反映这些更改。这是否意味着问题肯定不是 redux 需要非突变状态,还是我误解了 redux 在 copyState 的实现中的工作原理?
  • 鉴于现有信息,我认为您没有误解......我希望我也不是 :) 我也是 redux 的初学者,但我们可以肯定地说您的 copyState 函数提供正确的保证(无论其性能如何)。所以问题似乎出在其他地方:/
  • 我还推荐 deepCopy from lodash 而不是 JSON.parse(JSON.stringify(state)) 方法,主要是因为 lodash 的 deepCopy 保留 Date 对象,而 parse(stringify(state)) 会给你留下字符串而不是 @ 987654330@ 个对象。
【解决方案2】:

您的 copyState() 函数不会改变您的状态。没事。而对于阅读这个问题的其他人,直接去也可以

const newState = JSON.parse(JSON.stringify(oldState));

获取深层副本。感觉不干净,不过还可以。

您没有看到订阅运行的原因可能是 Redux 在复制之前将新状态(reducer 函数的输出)与现有状态进行了比较。如果没有差异,则不会触发任何订阅。因此,我们从不直接改变状态而是返回一个副本的原因——如果我们改变了状态,就永远不会检测到变化。

另一个原因可能是我们不知道您的代码中的 dispatchAction() 究竟做了什么。如果它是异步的(可能是因为中间件?),直到下一行的 console.log() 之后才会应用更改。

【讨论】:

    猜你喜欢
    • 2019-03-19
    • 2017-09-26
    • 1970-01-01
    • 2017-10-15
    • 2020-08-06
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多