简体   繁体   中英

Filter array of objects into new arrays

In React I have:

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

Producers Array:

     {
    "_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"

}

Right now I have all objects in state.Producers and I want to put any object that has the value state.Producers.Country === "France" (and so on for all the countries).

This is how I'm setting state:

    loadProducers = () => {

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

so I was thinking I need another .then statement after setting state for producers and then .filter for each country, but I can't seem to get it to work.

Assuming you res.data has a structure of [{Country: string}, {Country: string}...] , you could create a updatedState object and push the items into it.

Something like this:

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));
}

You can do it this way.

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));
}

Hope this helps.

React.Component#setState() does not return anything so a Promise#then() will have an undefined passed to it's callback. To avoid this, instead pass a callback to setState() so that it runs after the state update, but you should use the proper method and use the life cycle React.Component#componentDidUpdate() . The are many reasons you should want to use the life cycle including so that you can change where your data source comes from easily without changing how the state derives itself, the life cycle will need little to no maintenance, and it will always operate when the component gets updated meaning you won't have timing issues based on racing asynchronous conditions.

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;
    })
  }
}

This is guaranteed to run on a state update in a safe manner in a class, and keep your concerns(fetch) and derivatives(derived structures) separate and easy to maintain.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM