4
votes

Comment mettre à jour plusieurs propriétés d'état avec immer.js

Je me demande s'il est possible de mettre à jour plusieurs propriétés d'état avec immer.js en un seul "appel".

Disons que j'ai état : p >

case UPDATE_SEARCH_PAGE:
  return Object.assign({}, state, action.payload)

Et créateur d'action :

  this.props.updateSearchPage({
    isUserLogged: true,
    menuIsClosed: true,
    dataArray: ["dog","cat","owl"]
  })

J'utilise ensuite ce créateur d'action code > dans le composant React comme ceci:

export function updateSearchPage(data) {
  return {
    type: UPDATE_SEARCH_PAGE,
    payload: data
  };
}

L'idée est que je veux mettre à jour plusieurs propriétés d'état en même temps. Mais je ne sais pas de quelles propriétés il s'agit à l'avance. Je sais faire ça avec un simple réducteur:

export const initialState = {
  isUserLogged: false,
  menuIsClosed: false,
  mobileMenuIsClosed: true,
  dataArray: ["dog","cat"],
};

Mais comment mettre à jour plusieurs propriétés d'état avec immer en même temps ? Lorsque les propriétés d'état (lesquelles doivent être mises à jour) sont inconnues à l'avance.


0 commentaires

3 Réponses :


1
votes

Immer vous donne un état brouillon que vous pouvez modifier. Dans les coulisses, il utilise des proxies ES6 pour découvrir ce que vous avez changé et appliquer de manière immuable vos modifications à l'état d'origine.

En gros, vous pouvez faire exactement la même chose que vous faites maintenant, mais en utilisant l'API Immer: p>

const newState = produce(this.state, draft => {
  draft.propertyOne = 'newValue'
  draft.propertyTwo = 42
})

Si, à la place, vous savez quelles propriétés sont modifiées, vous pouvez faire quelque chose comme:

import produce from 'immer'

const newState = produce(this.state, draft => Object.assign({}, draft, payload))


1 commentaires

Merci d'avoir répondu!



4
votes

Vous pouvez faire défiler action.payload comme suit:

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
    }
  }

Aussi: rappelez-vous que sur les versions récentes d'immer, il est parfaitement légitime de renvoyer un objet, donc faire return Object.assign ({}, state, action.payload) est toujours valide dans un appel produire .


7 commentaires

Ok, pouvez-vous mettre à jour votre réponse concernant Object.assign, avec un exemple dans produire ? :)


C'est fait ... mais c'est clairement documenté sur la documentation de l'immersion: github.com/mweststrate/immer#reducer -exemple


Merci pour le lien et la réponse.


juste une question, quelle est la meilleure façon de restaurer initialState avec Immer? Comme draft = undefined ou draft = initialState , quand case RESET_SEARCH_PAGE ?


Il suffit de renvoyer initialState pour ce que j'ai écrit au bas de la réponse


Donc vous voulez dire case RESET_SEARCH_PAGE: Object.assign ({}, state, initialState); break; ? Donc, state ici et non draft , n'est-ce pas?


Si je reçois votre question: juste case RESET_SEARCH_PAGE: return initialState;



3
votes

Avec ES6, vous pouvez le faire de cette manière:

export const state = produce((draft, action) => {
  switch (type) {
    case UPDATE_SEARCH_PAGE:
      return {...draft, ...action.payload}
  }
}, initialState)

Dans ce cas, cela fonctionne de la même manière que sans Immer. Toutes les propriétés seront fusionnées (fusion superficielle) dans l'état. Si vous avez besoin de remplacer l'état, renvoyez simplement action.payload


0 commentaires