两个不可变的列表 - 如何使三重平等工作?

时间:2016-01-26 10:37:48

标签: javascript reactjs immutability redux immutable.js

假设我们有一个使用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正确地指出,深度平等会有所帮助,但这应该是最后的手段。

无论如何,我只是应用已接受的解决方案,问题就会解决,谢谢大家! ;)

2 个答案:

答案 0 :(得分:15)

你永远不能拥有不可变结构的严格相等,因为Immutable.js对象本身就是唯一的。

您可以使用.is函数,它接受两个不可变对象并比较它们中的值。这是有效的,因为不可变结构实现了equalshashCode

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存储为商店中的属性。仅在发生添加/删除所选项目或切换项目选择的操作时更新此列表,而不是在项目的其他任意属性更新时更新。