The spread operator (...
) doesn't quite do what you think it does. So according to the ECMAScript definition, it's a way of iterating over an Objects enumerable properties. You've got a pretty bad design of your state though which will become difficult to manage as you add complexity.
Array Spread Operator
This just iterates over an Array as a simpler way of creating new Array's from existing ones. Consider the following:
const old = ['b', 'c'];
const newArr = ['a', ...old, 'd']; // ['a', 'b', 'c', 'd']
Your problem can be solved by doing:
case('ADD_DEVICE_KEY'): {
return [
...state.slice(0, i),
{...state[i], likes: [...[state[i].likes], action.payload], // We're creating a new array here which is has the values of state[i].likes and also whatever we add to it
...state.slice(i+1)
]
** EDIT ** As Felix Kling pointed out in the comments below. This is actually an Array Spread Element.
State Design
It's likely you're going to run into issues with managing your state, it's much easier to store your state as an object.
Let's assume your state refers as user id, think of the ways this would be easier to refer to:
{
'1234567890': {
"code": "AAAAAAA",
"caption": "blah blah blah",
"likes": [
"ABCDEFG",
"BACDEFG"
],
"display_src": "https://pbs.twimg.com/profile_images/1044686525/Get_Some.jpg"
},
1234567890: {
"code": "BBBBBBB",
"caption": "nah fam",
"likes": [
"ABCDEFG",
"BACDEFG",
"CBADEFG"
],
"display_src": 'http://got-crossfit.com/wp-content/uploads/2014/04/get-some-rest.jpg'
}
]
Now, if you want to use that data all you need to do props[userId]
rather than (assuming you have some complex logic for finding i
consistently elsewhere in a way that is sane and can look up users; for(const user of props) { if (user.id === userId) return user }
, the first is cleaner, easier to destructure in child components and just nicer to read. You're letting the JS compiler do that for you, I really can't think of a good reason to store your state as an Array (particularly considering an Array for most purposes is just an Object with numeric keys).
By doing that you easily add the device id by using this:
switch(action.type) {
case('ADD_DEVICE_ID'): {
return {
...state,
[action.payload.userId]: Object.assign({}, action.payload.userId, { likes: { deviceId: action.payload.deviceId } })
}
}
}
Here we're resetting returning a new object, the rest of the state says the same, including the userId object with the exception of likes; which now has a deviceId field set to whatever we pass in. A much cleaner and easier to rationalise method.