user1665355
user1665355

Reputation: 3393

How to update multiple state properties with immer.js

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

Answers (3)

Dron007
Dron007

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

keul
keul

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

0xc14m1z
0xc14m1z

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

Related Questions