映射ImmutableJS集合

时间:2017-11-06 22:24:29

标签: javascript immutable.js

我有一个看起来像这样的ImmutableJS结构:

let state = fromJS({
  // ...
  foo: [{
    bar: ['id1', 'id2']
  },{
    bar: ['id2', 'id3']
  }]
});

我想要映射foo并针对每个项目,将相关的bar与另一个ID数组进行过滤,以排除(idsToExclude)。

我想出了这个:

const idsToExclude = ['id3', 'id4'];
state = { 
    ...state, 
    foo: state.get('foo').map((i) => 
        i.set(['bar'], i.get(['bar']
            .filterNot(b => idsToExclude.some(id => id === b)))) 
};

是否有更好,更惯用或更简洁的方式?

我问,因为这看起来很冗长。

2 个答案:

答案 0 :(得分:0)

我认为你可以使用.update让它变得更清洁,尽管这仍然相当长。您还可以将.some(id => id === b)简化为.contains(b)

state = state.update('foo', foo => 
    foo.map(item => 
        item.update('bar', 
            bar => bar.filterNot(
                id => idsToExclude.contains(id)))));

答案 1 :(得分:0)

现有代码存在一些问题:

  • state = {...state}正在创建一个普通的JS对象,而不是Immutable.js Map,并且它不会正确地将新的foo合并到state的字段中。
  • 我非常确定getset只接受一个key,而不是数组。要将密钥数组用作路径,请使用getInsetIn

如果您可以在数据结构中使用不可变Set而不是Lists,那么您可以使用subtract之类的集合操作来简化代码:

import {fromJS, Set} from 'immutable'

const initState = fromJS({
  // ...
  foo: [
    {bar: Set(['id1', 'id2'])},
    {bar: Set(['id2', 'id3'])}
  ]
})
const idsToExclude = fromJS(['id3', 'id4'])
const finalState = initState.update('foo', foo =>
  foo.map(element =>
    element.update('bar', set =>
      set.subtract(idsToExclude)
    )
  )
)

即使没有在您的数据结构中存储Set,您也可以在突变期间暂时使用它们:

const initState = fromJS({
  // ...
  foo: [
    {bar: ['id1', 'id2']},
    {bar: ['id2', 'id3']}
  ]
})
const idsToExclude = fromJS(['id3', 'id4'])
const finalState = initState.update('foo', foo =>
  foo.map(element =>
    element.update('bar', list =>
      list.toSet().subtract(idsToExclude).toList()
    )
  )
)