Reputation: 3393
I wonder if it is possible to update multiple properties of state with immer.js
in one "call".
Say I have state
:
export const initialState = {
isUserLogged: false,
menuIsClosed: false,
mobileMenuIsClosed: true,
dataArray: ["dog","cat"],
};
And action creator
:
export function updateSearchPage(data) {
return {
type: UPDATE_SEARCH_PAGE,
payload: data
};
}
I then use that action creator
in React component like this:
this.props.updateSearchPage({
isUserLogged: true,
menuIsClosed: true,
dataArray: ["dog","cat","owl"]
})
The idea is that I want to update several properties of state at the same time. But I dont know which properties it is in advance. I know how to do it with a simple reducer:
case UPDATE_SEARCH_PAGE:
return Object.assign({}, state, action.payload)
But how to update several properties of state with immer at the same time
? When the state properties (which one should update) are unknown in advance.
Upvotes: 7
Views: 11339
Reputation: 121
With ES6 you can do it this way:
export const state = produce((draft, action) => {
switch (type) {
case UPDATE_SEARCH_PAGE:
return {...draft, ...action.payload}
}
}, initialState)
In this case it works the same way as without Immer. All properties will be merged (shallow merge) into state. If you need to replace the state just return action.payload
Upvotes: 4
Reputation: 7819
You can cycle on action.payload
like the following:
const yourReducer = (state, action) =>
produce(state, draft => {
switch (action.type) {
case UPDATE_SEARCH_PAGE:
Object.entries(action.payload).forEach(([k, v]) => {
draft[k] = v;
})
break;
// ... other
}
}
Also: remember that on recent versions of immer is perfectly legit to returns an object, so doing return Object.assign({}, state, action.payload)
is still valid inside a produce
call.
Upvotes: 9
Reputation: 3725
Immer gives you a draft state that you can edit. Behind the scenes it uses ES6 proxies to discover what you changed and apply in an immutable way your edits to the original state.
Basically, you can do the exact same thing you do right now, but using the Immer api:
import produce from 'immer'
const newState = produce(this.state, draft => Object.assign({}, draft, payload))
If you, instead, know what properties are changed, you can do something like:
const newState = produce(this.state, draft => {
draft.propertyOne = 'newValue'
draft.propertyTwo = 42
})
Upvotes: 2