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

mse*_*mys 10 javascript immutability reactjs immutable.js redux

假设我们有一个使用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?
Run Code Online (Sandbox Code Playgroud)

你可以在这里玩它: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}
]
Run Code Online (Sandbox Code Playgroud)

我想只将选定的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);
Run Code Online (Sandbox Code Playgroud)

问题是,如果我设置其他属性:

{id: 1, selected: true, note: "The force is strong with this one"}
Run Code Online (Sandbox Code Playgroud)

这导致状态改变和SomePlainComponent重新渲染,尽管所选择的ID列表完全相同.如何确保纯渲染器有效?

编辑一些额外的信息

对于反应纯渲染,我使用了反应 - 纯渲染的 mixin :

export default function shouldPureComponentUpdate(nextProps, nextState) {
    return !shallowEqual(this.props, nextProps) ||
           !shallowEqual(this.state, nextState);
}
Run Code Online (Sandbox Code Playgroud)

因为它不知道可以不可变的道具,所以它们被视为已改变,即

this.props = {
    ids: ImmutableList1
}

nextProps = {
    ids: ImmutableList2
}
Run Code Online (Sandbox Code Playgroud)

虽然两个属性ids都是内容相同的,但它们是完全不同的对象,不会通过ImmutableList1 === ImmutableList2测试和shouldComponentUpdate返回true.@Gavriel正确指出深度平等会有所帮助,但那应该是最后的选择.

无论如何,我只是应用公认的解决方案,问题将得到解决,谢谢大家!;)

Hen*_*son 16

你永远不能拥有不可变结构的严格相等,因为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
Run Code Online (Sandbox Code Playgroud)