Reputation: 518
I have a react component 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?
Upvotes: 1
Views: 5037
Reputation: 31833
That 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);
Upvotes: 6
Reputation: 15246
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);
Upvotes: 0
Reputation: 802
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);
Upvotes: 1
Reputation: 6824
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
Upvotes: 0