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"
}
]
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"
}
]
Share
Improve this question
edited Jan 23, 2019 at 18:54
asked Jan 23, 2019 at 15:57
user10803047user10803047
12
-
What is the structure of the data you are expecting to receive? You can only use
[]
to destructure an array or an iterable; you would use{}
to destructure an object. – wlh Commented Jan 23, 2019 at 16:06 -
1
You should checkout the output of
console.log(JSON.stringify( response.data,undefined,2))
The error is similar asconst [a,b]=22
– HMR Commented Jan 23, 2019 at 16:07 -
@HMR hey can you tell why your using undefined and 2 in your console and I am able to see the value in the console for this line
console.log(JSON.stringify( response.data,undefined,2))
– user10803047 Commented Jan 23, 2019 at 20:57 -
1
What @HMR and I were doing with this format of
console.log()
in general making the full (or rather desired) depth of the Object you're logging visible. Using a modern browser console.log(someObj) because it will allow you to inspect the entirety of the Object in the 'dev tools' console, but in a server-side environmentconsole.log()
will only give you[Object]
and usingJSON.stringify(obj)
, which converts the object to a string, will still only show you the 'fist' level of that Object.... – cantuket Commented Jan 23, 2019 at 21:14 -
1
@cantuket I use JSON.stringify because even in a browser when you expand a logged object it shows the object as it is now; not as it was at the time of logging (you may have mutated the object to fit or break the code close to the log) For example:
const arr = [{name:'Ben'}];console.log(arr);arr[0].name='Jerry';
when you expand the logged object it shows name is Jerry but that wasn't the name at the time of logging. The 2 inJSON.stringify(obj,undefined,2)
is the amount of spaces used for the tab size of the formatted JSON. – HMR Commented Jan 25, 2019 at 7:48
2 Answers
Reset to default 2EDIT:
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 remended 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...
- Data structure of
response.data
. Can you provide result ofconsole.log( JSON.stringify( response.data, null, 5) )
- 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)