【问题标题】:Updating an ImmutableJS Map更新 ImmutableJS 映射
【发布时间】:2017-07-18 02:33:25
【问题描述】:

我正在尝试根据一些传入的分页数据更新Immutable.Map,在我的数据结构中构建顶级索引。

传入的数据如下所示:

[
  {
    identifier: ADFASD,
    tags: [ tag1, tag2]
  },  {
    identifier: GGHYX,
    tags: [ tag2, tag3]
  },
]

想要的结果

{
  taggedArticleList: {
     tag1: [ADFASD],
     tag2: [ADFASD, GGHYX],
     tag3: [GGHYX],
  }
}

我正在重构的当前 JS 函数(有效):

let taggedArticleList = {}
action.data.response.results.map((article) => {
    article.tags.map((tag) => {
        let key = taggedArticleList[tag] || (taggedArticleList[tag] = [];
        key.article.push(article.identifier)
    });
});
return taggedArticleList

还有我目前的 ImmutableJS 尝试:

.update('taggedArticleList', taggedArticleList =>
    Immutable.Map(
        Immutable.fromJS(action.data.response.results).map(
            article =>
                article.get('tags').map(
                    tag =>
                        [
                            tag,
                            taggedArticleList.has('tag')
                                ? taggedArticleList.get(tag).push(article.get('identifier'))
                                : Immutable.List().push(article.get('identifier'))
                        ]
                )
        )))

我的方法是通过传入数据“文章”进行映射,然后通过它们的“标签”进行映射,并检查现有的taggedArticleList 是否具有密钥 - 如果它确实将新标识符推送到它上面,否则创建一个新的Immutable.List 然后推它。我试图劫持Immutable.Map 构造函数,它接受[key, value] 类型结构作为创建自身的默认方式。

返回的数据结构给了我一个奇怪的tag<List> 键和一个List[tag, List[identifier]] 返回形状。非常感谢任何建议。

【问题讨论】:

    标签: ecmascript-6 immutable.js


    【解决方案1】:

    我假设您的传入数据也是不可变的(您在尝试的解决方案中暗示了这一点),即

    • 整个传入数据集是一个不可变列表,
    • 每篇文章都是一个不可变映射,并且
    • 每个标签系列都是一个不可变列表。

    我的答案不包括taggedArticleList 键,因为该级别的对象层次结构不会增加或消除这个问题的复杂性。我假设您将其包含在内,因为它对您的特定用例很重要,但对于此答案来说只是额外的混乱。

    请注意,在下面的代码中,reduce 函数的累加器,即jsMap,是一个 普通 JavaScript Map 对象,不是一个 Immutable Map 对象,即jsMap 是可变的。此解决方案需要这种可变性才能工作,并且(我相信)不会违反使用不可变数据的原则,因为它只是在处理原始传入数据期间使用的中间变量,最终转换为不可变数据地图。

    如上所述,此解决方案假定您的传入数据也是不可变的。但是,如果它只是“普通”(可变)JavaScript 对象数据,您唯一需要做的就是将 article.get('tags') 更改为 article.tags 并将 article.get('identifier') 更改为 article.identifier

    const incoming = Immutable.List([
      Immutable.Map({
        identifier: 'ADFASD',
        tags: Immutable.List([ 'tag1', 'tag2'])
      }),
      Immutable.Map({
        identifier: 'GGHYX',
        tags: Immutable.List([ 'tag2', 'tag3'])
      }),
    ]);
    
    const updated = Immutable.Map(
        incoming.reduce((jsMap, article) => {
            article.get('tags').forEach(tag => {
                jsMap.set(tag, Immutable.List([
                    ...(jsMap.has(tag) ? jsMap.get(tag) : []),
                    article.get('identifier')
                ]));
            });
            return jsMap;
        }, new Map()) // NOTE: this is a regular JavaScript map, NOT an Immutable map
    );
    
    console.log(updated);
    
    // console output: Map { "tag1": List [ "ADFASD" ], "tag2": List [ "ADFASD", "GGHYX" ], "tag3": List [ "GGHYX" ] }
    

    作为旁注,还请注意,在您的原始解决方案中,无论是原始的工作 JavaScript 代码还是不工作的不可变代码,我认为您使用 map 不正确,即使在第一种情况下,你最终会得到你想要的解决方案。 map 是一个函数,旨在返回一个数组,其中每个元素对应于原始数组中的一个元素。您正在使用它来按顺序获取每个元素,然后只需使用该元素来修改其他数据而不从该函数返回任何内容。事实上,您想要的最终结果确实 not 具有映射(即对应)到原始数组的数组元素。事实上,结果甚至不是一个数组,它是一个对象(或者,更准确地说,一个 Map ......我知道,它会让人感到困惑)。我认为在这种情况下,您可能应该使用forEach 而不是map。这次您的代码可以正常工作,但是以这种方式使用 map 函数可能会在将来导致混乱/错误。您使用它的方式并不违法,并且正如您所展示的那样,它可以工作。但是,map 的用途并非如此。只是想我会给你一个提示。

    【讨论】:

      猜你喜欢
      • 2020-01-23
      • 1970-01-01
      • 1970-01-01
      • 2018-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多