I have a react ponent where I am trying to spread objects into the state in the constructor.
constructor() {
super()
const shapesArray = [1, 2, 3]
let renderStates = shapesArray.map((el, i) => {
return {['shape'+i]: 'black'}
})
this.state = { ...renderStates }
console.log(this.state)
}
I want to access the colors by doing this.state.shape0
,
but when I console log this.state
, I get this:
instead of Object {shape0: "black", shape1: "black", shape2: "black"}
.
What am I doing wrong here?
I have a react ponent where I am trying to spread objects into the state in the constructor.
constructor() {
super()
const shapesArray = [1, 2, 3]
let renderStates = shapesArray.map((el, i) => {
return {['shape'+i]: 'black'}
})
this.state = { ...renderStates }
console.log(this.state)
}
I want to access the colors by doing this.state.shape0
,
but when I console log this.state
, I get this:
instead of Object {shape0: "black", shape1: "black", shape2: "black"}
.
What am I doing wrong here?
Share Improve this question edited Sep 7, 2018 at 1:00 Patrick Roberts 52.1k10 gold badges117 silver badges163 bronze badges asked May 13, 2017 at 19:10 8ctopotamus8ctopotamus 5181 gold badge7 silver badges13 bronze badges 4- 1 You're not using spread syntax in an array literal here??? That should be a syntax error in ES6 (maybe you have enabled some experimental babel stuff) – Bergi Commented May 13, 2017 at 20:00
- Btw, for indexed values such as your shape collection, you should always use an object. – Bergi Commented May 13, 2017 at 20:02
-
1
Your
renderStates
is an array. Shouldn't you use[...renderStates]
? – Pankaj Shukla Commented May 13, 2017 at 20:10 -
...
is not an operator! – Felix Kling Commented May 14, 2017 at 1:23
4 Answers
Reset to default 6That is because you are spreading an Array into an Object. Arrays are actually objects with (usually) sequential integral strings as their keys. These keys are the indices of the array.
As shown below, map
takes an array and produces another array
const shapesArray = [1, 2, 3];
const renderStates = shapesArray.map((el, i) => {
return {
['shape' + i]: 'black'
};
});
console.log(renderStates);
When spreading into an Object, the value of each own enumerable property in the source Object is added to the target under its respective key. Since the keys of an array are its indices you end up with an Object with a property for each element of the Array. The name of each property is its index in the array.
To achieve what you want, you can use Array.prototype.reduce
to build an object from the array with the names created in the mapping process.
const shapesArray = [1, 2, 3];
const renderStates = shapesArray
.map((el, i) => {
return {
['shape' + i]: 'black'
};
})
.reduce((o, element) => {
Object.keys(element).forEach(key => o[key] = element[key]);
return o;
}, {});
console.log(renderStates);
Of course this itself can be written more elegantly by spreading the object inside of reduce.
const shapesArray = [1, 2, 3];
const renderStates = shapesArray
.map((el, i) => {
return {
['shape' + i]: 'black'
};
})
.reduce((o, element) => ({...o, ...element}), {});
console.log(renderStates);
As an optimization to aluan-haddad's answer, reduce can handle the logic that was in map
const shapesArray = [1, 2, 3];
const renderStates = shapesArray
.reduce((acc, _, i) => ({
...acc,
['shape' + i]: 'black',
}), {});
console.log(renderStates);
renderStates
is an array which has integer properties starting from 0 or the array indices if you want to be specific, so {...renderStates}
will take each index, and create a mapping from this index to the value corresponding to that index, to achieve what you are looking for, you need to reduce your renderStates
array to an object like so
let renderStates = shapesArray.map((el, i) => {
return {['shape'+i]: 'black'}
}).reduce((resultObj, currentShape,index) => resultObj['shape'+index] = currentShape['shape'+index]), { });
renderStates
is now an object, and you can spread it and it will produce the result you want
No need to iterate twice over array. Use reduce:
const shapesArray = [1, 2, 3];
const renderStates = shapesArray.reduce((accumulator, i) => {
accumulator['shape' + i] = 'black';
return accumulator;
}, {});
console.log(renderStates);