【问题标题】: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 数组中的内容的示例。非常感谢所有输入!

标签: javascript arrays reactjs filter


【解决方案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 是生命周期方法,不需要绑定。
  • 很好,删除它
猜你喜欢
  • 1970-01-01
  • 2018-02-14
  • 2020-02-07
  • 2021-08-27
  • 1970-01-01
  • 1970-01-01
  • 2020-11-01
  • 1970-01-01
  • 2018-11-12
相关资源
最近更新 更多