假设我们有一个使用Facebook的伟大Immutable.js创建的不可变对象。我想比较使用.map
或.filter
从单一来源生成的两个列表,并确保它们相等。在我看来,当使用map / filter时,你正在创建一个与前一个对象无关的新对象。如何使三重平等===
起作用?它有意义吗?
var list = Immutable.List([ 1, 2, 3 ]);
var list1 = list.map(function(item) { return item; })
var list2 = list.map(function(item) { return item; })
console.log("LIST1 =", list1.toJS()) // [1, 2, 3]
console.log("LIST2 =", list2.toJS()) // [1, 2, 3]
console.log("EQUAL ===?", list1===list2); // false! Why? How?
您可以在此处播放:http://jsfiddle.net/eo4v1npf/1/
我正在使用React + Redux构建应用程序。我的州有一个包含项目的列表,其中包含属性selected
:
items: [
{id: 1, selected: true},
{id: 2, selected: false},
{id: 3, selected: false},
{id: 4, selected: true}
]
我只想将选定的ID 传递给另一个容器,所以我尝试使用简单的connect
:
function getSelectedIds(items) {
return items
.filter((item) => item.get("selected"))
.map((item) => item.get("id"));
}
export default connect(
(state: any) => ({
ids: getSelectedIds(state.get("items"))
})
)(SomePlainComponent);
问题是,如果我设置了其他属性:
{id: 1, selected: true, note: "The force is strong with this one"}
这会导致状态发生变化并SomePlainComponent
重新呈现,尽管所选ID的列表完全相同。如何确保纯渲染器有效?
对于反应纯渲染,我使用了来自react-pure-render的mixin:
export default function shouldPureComponentUpdate(nextProps, nextState) {
return !shallowEqual(this.props, nextProps) ||
!shallowEqual(this.state, nextState);
}
由于它不知道道具可以是不可变的,所以它们被视为已改变,即
this.props = {
ids: ImmutableList1
}
nextProps = {
ids: ImmutableList2
}
虽然两个属性ids
按内容相同,但它们是完全不同的对象,不会通过ImmutableList1 === ImmutableList2
测试,而shouldComponentUpdate
会返回true
。 @Gavriel正确地指出,深度平等会有所帮助,但这应该是最后的手段。
无论如何,我只是应用已接受的解决方案,问题就会解决,谢谢大家! ;)
答案 0 :(得分:15)
你永远不能拥有不可变结构的严格相等,因为Immutable.js对象本身就是唯一的。
您可以使用.is
函数,它接受两个不可变对象并比较它们中的值。这是有效的,因为不可变结构实现了equals
和hashCode
。
var map1 = Immutable.Map({a:1, b:1, c:1});
var map2 = Immutable.Map({a:1, b:1, c:1});
console.log(Immutable.is(map1, map2));
// true
答案 1 :(得分:1)
如果您希望保持组件纯净并使用===
,那么您还可以对Redux状态进行非规范化,并将selectedIds存储为商店中的属性。仅在发生添加/删除所选项目或切换项目选择的操作时更新此列表,而不是在项目的其他任意属性更新时更新。