将对象数组过滤到新数组中

Posted

技术标签:

【中文标题】将对象数组过滤到新数组中【英文标题】:Filter array of objects into new arrays 【发布时间】:2019-09-20 12:01:54 【问题描述】:

在 React 中我有:

    state = 
     Producers: [], 
     France: [],
     Spain: [],
     Germany: [],
     Portugal: [],
     Greece: [],
     Austria: [],
     isLoading: false
     ;

生产者数组:

     
    "_id" : ObjectId("5cc0bf1815cc7a2225edab0b"),
    "Code" : "FPG-BCH14",
    "URL" : "/jSQcl",
    "Just_In" : "",
    "Country" : "France",
    "Region" : "Burgundy"
,

    "_id" : ObjectId("5cc0bf1815cc7a2225edab0c"),
    "Code" : "FPG-CHA17",
    "URL" : "/XPxx",
    "Just_In" : "",
    "Country" : "France",
    "Region" : "Burgundy"  
,

    "_id" : ObjectId("5cc0bf1815cc7a2225edab0d"),
    "Code" : "FPG-BPN16",
    "Just_In" : "",
    "Country" : "France",
    "Region" : "Burgundy"

,


    "_id" : ObjectId("5cc0bf1815cc7a2225edab0e"),
    "Code" : "PAP-VIN17",
    "Country" : "Portugal",
    "Region" : "Vinho Verde",
    "Subregion" : "Lima"


现在我在state.Producers 中有所有对象,我想放置任何具有state.Producers.Country === "France" 值的对象(所有国家/地区等等)。

这就是我设置状态的方式:

    loadProducers = () => 

     API.getProducers()
     .then(res => 
     this.setState(Producers: res.data)
     )
     .catch(err => console.log(err));
       

所以我想在为生产者设置状态后,我需要另一个 .then 声明,然后为每个国家/地区设置 .filter,但我似乎无法让它发挥作用。

【问题讨论】:

你能发布一个你的数据结构是如何设置的例子吗? (res.data 对象) 请把你的问题澄清一下,比如你到底想达到什么目标,你想如何比较? 通常最好不要像这样复制状态。如果Producers 已经拥有所有数据,只需在渲染前对其进行过滤:const france = state.producers.filter(p => p.Country === "France") 谢谢@RobertMennell @BrunoMonteiro,我正在努力进一步理解这一点......我已经编辑了我上面的问题以包含state.Producers 数组中的内容的示例。非常感谢所有输入! 【参考方案1】:

假设您res.data 的结构为[Country: string, Country: string...],您可以创建一个updatedState 对象并将项目推入其中。

类似这样的:

const loadProducers = () => 
    API.getProducers()
    .then(res => 
        const updatedState = 
            Producers: [], 
            France: [],
            Spain: [],
            Germany: [],
            Portugal: [],
            Greece: [],
            Austria: []
        ;
        res.data.forEach((item) => 
            updatedState[item.Country].push(item);
        )
        // This line if you also need everything inside Producers
        updatedState.Producers = res.data;

        this.setState(updatedState);
    )
    .catch(err => console.log(err));

【讨论】:

这样容易出现时序问题,因此可能不可靠 这意味着维护 fetch 也意味着维护派生状态 感谢您的评论,但您所说的“保持 fetch 也意味着保持派生状态”是什么意思? 如果他们从使用 fetch 更改为使用不使用 .then 的库,或者他们决定将其包装在不同的库中以获得更易于维护的固执的响应检查器(任何 400 到不同的回调,200成功)?他们需要维护更多的逻辑,而不仅仅是确保对象上的相同键是具有要放入状态的国家/地区键的对象数组,他们总是必须调整函数 嗯...不过,这听起来没有问题。这个问题与 javascript 以及如何解析对多个数组的响应有关。如果方法更改为不使用承诺,那么无论如何都需要重构。我明白你的意思,但不同意投反对票......如果我对你的回答投反对票,说如果他们不想将密钥从“国家”更改为其他东西,你不会处理...... 【参考方案2】:

你可以这样做。

loadProducers = () => 
 API.getProducers()
  .then(( data ) =>
    // Here we reduce all the results with respect to the country associated with
    updatedState = data.reduce((res, obj) => 
     if (!res[obj.Country]) 
       res[obj.Country] = [];
     
     return  ...res, [obj.Country]: [...res[obj.Country], obj] 
    , );

    // Push all the data into Producers provided that you need it here. else you can ignore this line :)
    updatedState.Producers = data;

    //Finally update the state 
    this.setState(updatedState);
  ).catch(( response ) => console.log(response));

希望这会有所帮助。

【讨论】:

这样容易出现时序问题,可能不可靠 计时问题是什么意思?可能你应该提供更多的细节,而不是期望我们在你降价时谷歌。 如果我发出两个请求,它们几乎同时到达,但旧数据第二个到达,由于状态更新的异步性质而清除了新数据,会发生什么? 我想问题是关于如何做而不是在哪里做。 @RobertMennell 如果您有多个 api 并且每个 API 返回不同的数据结构,您是否会将您的状态限制在标准结构中,而不考虑当您正在进行多个 api 调用?在那种情况下,即使您的方法也无法维护,并且可能需要使用像 redux 这样的状态管理库。【参考方案3】:

React.Component#setState() 不返回任何内容,因此Promise#then() 将有一个未定义的传递给它的回调。为避免这种情况,请改为传递a callback to setState(),以便它在状态更新后运行,but you should use the proper method and use the life cycle React.Component#componentDidUpdate()。您应该使用生命周期的原因有很多,包括这样您就可以轻松更改数据源的来源,而无需更改状态本身的派生方式,生命周期几乎不需要维护,并且在组件得到更新,这意味着您不会遇到基于赛车异步条件的计时问题。

this.componentDidUpdate = function componentDidUpdate(
  previousProps,
  previousState
) 
  // wrap it in a comparison so that you don't infinitely loop
  if (//compare producers to previous producers here) 
    // they have changed, update state, use updater to prevent timing problems
    this.setState(state => 
      // keep changing data in sync
      // this also allows you to fetch changing data over time
      const update = ...state;
      state.producers.forEach(producer => 
        // safely initialize
        update[producer.Country] = update[producer.Country] || [];
        if (!update[producer.country].find(producer) 
          // push onto
          update[producer.Country].push(producer);
        
      );
      return update;
    )
  

这保证在类中以安全的方式在状态更新上运行,并使您的关注点(获取)和派生(派生结构)分开且易于维护。

【讨论】:

componentDidUpdate 是生命周期方法,不需要绑定。 很好,删除它

以上是关于将对象数组过滤到新数组中的主要内容,如果未能解决你的问题,请参考以下文章

将数组内相同值的对象合并为一个新对象,并将其中一个值相加到新对象中,而且重复的对象则不能加到新对象

如何解决尝试将对象数组中的数据存储到新对象中的错误

将一个类数组对象转化为数组的几种方法

js过滤数组中都为空的对象几种方式

根据字符串数组过滤对象数组

过滤的对象数组,nuxt,vue js