With Redux Toolkit you update nested data by assigning to it directly, like state.profile.address.city = action.payload. createSlice runs reducers through Immer, which turns those writes into an immutable update and copies only the objects on the changed path.
Common patterns:
- Replace a nested object by assigning a new value to its property, as
updateAddressdoes below. - Update one deep field by assigning to that field, as
updateCitydoes. - Update an item in an array by finding it first and then changing it, like
state.items.find(item => item.id === id).
Arrays also support push and index assignment directly on the draft.
Two rules prevent bugs. Either mutate the draft or return a new state, never both in one reducer. And never reassign state itself, because that only changes the local variable.
For data nested many levels deep, normalizing it by ID keeps reducers flat. You can still return a new state object when that logic reads more clearly.
const userSlice = createSlice({
name: 'user',
initialState: {
profile: {
name: '',
address: {
street: '',
city: ''
}
}
},
reducers: {
updateAddress: (state, action) => {
// Direct assignment works with Immer
state.profile.address = action.payload;
},
updateCity: (state, action) => {
state.profile.address.city = action.payload;
}
}
});
This answer doesn't lend itself to a diagram - it reads best . No credits were charged.
Why there's no diagram: “”
The interactive diagram is below the answer - jump to diagram ↓ · Below it, the related concept . Jump to it ↓
The diagram below the answer is the concept . Jump to it ↓