不可变与 javascript 数组、对象 - 什么是正确的平衡?



我正在构建我的堆栈,其中包括react、redux和不可变。我的redux存储是用不可变的映射和列表构建的。然而,在react组件级别,操作普通的js数组和对象更容易。

那么平衡是什么呢?是否应该将状态中的不可变对象转换为所有组件的常规js,并将传递回reducer的数据转换回不可变以更新状态?

我目前正在逐个组件的基础上进行这项工作,但我有兴趣了解任何当前(事实上)的最佳实践。

在我看来,接受不可变并坚持它。即使在组件级别操作js数据类型似乎更容易,但不可变在良好实践和性能方面给你带来的优势是巨大的。

如果您在存储中使用不可变,甚至在组件中使用它。

TL;DR:

  • 商店是Immutable.Map
  • Store通过gettersselectors将数据转换为普通js对象来公开数据:const getFooItem(state, itemId) => state.getIn(['item',itemId]).toJS()
  • Dumbs组件通过props将数据作为普通js对象使用

Immutable.js用于您的redux Store

我认为您肯定应该为redux存储使用Immutable.js,因为它可以确保您保留一个不可变的存储。即使使用了新的ES6语法,它也比纯javascript更不容易出错。例如,假设您的状态的一部分如下:

state = {
items: {
'id1': {...your_fo_object_with_id1...},
'id2': {...your_fo_object_with_id2...},
etc.
}
}

现在你想用id2填充项目,所以你要写这样的东西:

return {
...state,
items: {
...items, //Do not forget this line, if you do, no error will be thrown, but your state will be in a bad state since all others items will be lost 
[action.id]: action.item
}
}

你注意到我的评论了吗?如果有可能做出这样的承诺(即忘记复制以前的状态),并产生如此大的影响,你可以肯定你迟早会成功的。问我怎么知道…

使用Immutable.js,这种错误可以通过语法本身来避免:

return state.updateIn(['items', 'id1'], () => Immutable.fromJS(action.item)))

使用普通js对象作为道具

在这里,这更多的是个人的偏好,但既然你想让你的组件尽可能地保持沉默,为什么他们会知道他们的道具是Immutable对象,并知道如何处理它们?

通常,为了避免不必要的渲染,在浅层比较道具时使用道具中的Immutable.js进行引用相等性检查是很诱人的。当你有非常嵌套的道具时,它实际上非常方便我认为非常嵌套的支柱是个坏主意。尽量保持组件道具的平面化,这样可以减少它们与数据模式的耦合,提高可重用性。

编辑

正如Raj R在评论中所说,您可以使用一些gettersselectors作为不可变存储和dumps组件之间的桥梁。这是完全合理的,因为gettersselectors根据定义与您的存储紧密耦合,因此它们可以接收处理不可变的数据,并通过将由您的dumps组件使用的普通js对象将它们打开到外部世界。

最新更新