简体   繁体   中英

Unhandled Rejection (TypeError): Invalid attempt to destructure non-iterable instance

I am trying to learn the map method. If I use this syntax response.data.map(d => I am able to iterate data array and see the results, but if I use this syntax response.data.map(([label, CustomStep]) => { , I am getting the error below:

Unhandled Rejection (TypeError): Invalid attempt to destructure non-iterable instance

Can you tell me how to fix it, so that in future I will fix it myself?

Providing my code snippet below:

axios
.get('http://world/sports/values')
.then(response => {
    console.log("sports--->", response.data.map(d => d.customFieldValueName));
    //this.setState({ playerRanks: response.data.map(d => d.customFieldValueName) });
    // es6 map
    //Unhandled Rejection (TypeError): Invalid attempt to destructure non-iterable instance
    this.setState({
        playerRanks: response.data.map(([label, CustomStep]) => {
            label.customFieldValueName
        })
    })
})

update 1:

hey, I saw in console, data is an array inside that there are so many objects

 data: Array(19)
        [
            {
                "customFieldValueCode": "player1",
                "customFieldValueName": "player1",
                "isActive": "Y"
            },
            {
                "customFieldValueCode": "player 2",
                "customFieldValueName": "player 2",
                "isActive": "Y"
            }
        ]

EDIT:

Based off the data structure provided you could modify your code to...

axios
.get('http://world/sports/values')
.then(response => {
    this.setState({
        playerRanks: response.data.map(obj => {
            return obj.customFieldValueName
        })
    })
})

OR

    ...
    response.data.map(({customFieldValueName}) => {
        return customFieldValueName;
    })
    ...

OR even...

    ...
    response.data.map(({customFieldValueName}) => customFieldValueName)
    ...

But this would be my recommended solution to provide type checking on you data and proper error handling...

axios
.get('http://world/sports/values')
.catch(err=> console.log(err))
.then(({data}) => {                       // Axios always returns an Object, so I can safely 'attempt' to destructure 'data' property 
    if (data && data.length) {            // making sure 'data' does exist, it is an Array and has > 0 elements
      this.setState({
        playerRanks: data.map(obj => {    // Not destructuring here in case obj isn't actually an Object
            if (obj && obj.customFieldValueName) return customFieldValueName;
            return null;
        }).filter(elem=> elem)            // BIG-O notation: This sequence is O(2N), as in iterates over the entire Array first with .map(), then iterates over the entire Array again with .filter() to clear out 'null' values
      })
    }
})

In order to prevent your returned Array above from having a bunch of null elements when they don't conform to our assertions, you can use an Array.reduce() method to 'filter' out any null s...

axios
.get('http://world/sports/values')
.catch(err=> console.log(err))
.then(({data}) => {                       // Axios always returns an Object, so I can safely 'attempt' to destructure 'data' property 
    if (data && data.length) {            // making sure 'data' does exist, it is an Array and has > 0 elements
      this.setState({
        playerRanks: data.reduce((acc,obj) => {    // Not destructuring here in case obj isn't actually an Object
            if (!obj || !obj.customFieldValueName) return acc; // If it doesn't meet assertions just return the existing accumulator (don't add another element .ie 'null')
            return [                        
                ...acc,                      // If it conforms to the assertions the return a new accumulator, by first spreading in all existing elements and the adding the new one (customFieldValueName)
                customFieldValueName
            ]
        },[])                      // BIG-O notation: This is O(1N) or O(N), as in it will only iterate over the Array one time and the reduce() function will filter out 'null' values at the same time
      })
    }
})

NOTE: I also just added .filter(elem=> elem) to the end of my first example, which does the same thing as the new .reduce() functionality, but does this in 1N not 2N operations.

PRE-logged data

Here's how the Array.map() method works...

[1,2].map(element=> {
// element === 1, first iteration,
// element === 2, second iteration
})

Here's how Array destructuring works...

[one, two, ...theRest] = [1,2,3,4,5]

// one === 1 and two === 2 and theRest = [3,4,5]

Here's how Object destructuring works...

{one, three, ...theRest} = {one: 1, two: 2, three: 3, four: 4, five: 5}

// one === 1 and three === 3 and theRest === {two: 2, four: 4, five: 5}
// notice order doesn't matter here (three vs two), but you need to access valid properties from the object you're deetructuring from

So based on the way you function is structured you are making the assumption that the data structure of response.data is...

response.data === [ 
   [ 
     { customFieldValueName: 'any value' }, // label
     {}                                     // CustomStep (this could be any value, not necessarily an Object) 
   ],
   [ 
     { customFieldValueName: 'any value' }, // label
     'any value'                            // CustomStep
   ]
]

I hope this helps conceptually, but if you'd like a workable solution we will need...

  1. Data structure of response.data . Can you provide result of console.log( JSON.stringify( response.data, null, 5) )
  2. Specific values you are trying to assign to the new this.state.playerRanks Array.

PS: A good way to see Object destructuring in action with your current code is to change...

.then( response => {

To

.then( ({data}) => {

In this case, you should be certain that response.data is an array of arrays, because for each iteration of response.data.map , the function you are providing to the map must receive an array to be able to successfully pull the label and CustomStep values, due to the syntax with which you are destructuring the function parameter.

Imagine data in the following example is the response.data and the parseData function is the function you are passing to the map :

let data = [
  [{ customFieldValueName: 'field name' }, { stepData: {} }],
  [{ customFieldValueName: 'another field name' }, { stepData: {} }]
];

let parseData = ([label, CustomStep]) => console.log(label.customFieldValueName);

parseData(data[0]); // prints out 'field name'

Otherwise, if response.data is an array of objects, which it seems like it is due to you successfully being able to run response.data.map(d => d.customFieldValueName) , you could update your map to this (if you simply want to pull the customFieldValueName value out of the object):

response.data.map(({ customFieldValueName }) => customFieldValueName)

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