If you're adding to the end, you spread out the other aspects of state in the new state object, then override data with the current contents of it followed by the new entry:
const newState = { // New state is an object, not an aray
...defaultState, // Get everything from defaultState
data: [ // Replace `data` array with a new array
{
...defaultState.data[0], // with the first item's contents
elements: [ // updating its `elements` array
...defaultState.data[0].elements,
newElement
]
},
...defaultState.data.slice(1) // include any after the first (none in your example)
]
};
Live Example:
const defaultState = {
isLoading: false,
data: [{
id: 1,
label: 'abc',
elements: [{ color: 'red', id: 1}],
}],
};
const newElement = {
colour: 'blue',
id: 1
};
const newState = { // New state is an object, not an aray
...defaultState, // Get everything from defaultState
data: [ // Replace `data` array with a new array
{
...defaultState.data[0], // with the first item's contents
elements: [ // updating its `elements` array
...defaultState.data[0].elements,
newElement
]
},
...defaultState.data.slice(1) // include any after the first (none in your example)
]
};
console.log(newState);
.as-console-wrapper {
max-height: 100% !important;
}
There's no getting around specifying the entry in data that you want (e.g., data[0]).
In a comment you've asked how to handle this:
Let's say data (present inside defaultState) has multiple objects entries in it. First object has id of 1, second one has id of 2. Now the newElement to be added has an id of 2. So the newElement should get added to the second object. Where in second object? Inside the elements property of the second object. The addition should not over-write existing entries in the elements array.
You'll need to find the index of the entry in data:
const index = defaultState.data.findIndex(({id}) => id === newElement.id);
I'm going to assume you know that will always find something (so it won't return -1). To then apply that index to the code above, you'd do this:
const newState = { // New state is an object, not an aray
...defaultState, // Get everything from defaultState
data: [ // Replace `data` array with a new array
...defaultState.data.slice(0, index), // Include all entries prior to the one we're modifying
{
...defaultState.data[index], // Include the entry we're modifying...
elements: [ // ...updating its `elements` array
...defaultState.data[index].elements,
newElement
]
},
...defaultState.data.slice(index + 1) // include any after the one we're updating
]
};
The only real change there is adding the ...defaultState.data.slice(0, index) at the beginning of the new data, and using index instead of 0.
Live Example:
const defaultState = {
isLoading: false,
data: [
{
id: 1,
label: 'abc',
elements: [{ color: 'red', id: 1}],
},
{
id: 2,
label: 'def',
elements: [{ color: 'green', id: 2}],
},
{
id: 3,
label: 'ghi',
elements: [{ color: 'yellow', id: 3}],
}
],
};
const newElement = {
colour: 'blue',
id: 2
};
const index = defaultState.data.findIndex(({id}) => id === newElement.id);
const newState = { // New state is an object, not an aray
...defaultState, // Get everything from defaultState
data: [ // Replace `data` array with a new array
...defaultState.data.slice(0, index), // Include all entries prior to the one we're modifying
{
...defaultState.data[index], // Include the entry we're modifying...
elements: [ // ...updating its `elements` array
...defaultState.data[index].elements,
newElement
]
},
...defaultState.data.slice(index + 1) // include any after the one we're updating
]
};
console.log(newState);
.as-console-wrapper {
max-height: 100% !important;
}
state.data[0].elements? Notstate.data?newElementhas the same structure thanstate.data[0].elementselements, so it seems to belong to it. Do you want to mixstate.dataelements with different model?elementsof that object in thedataarray that has the sameidas that object. So theidof the object and thenewElementshould match.