Redux: Question : Mutation d'un objet interne dans un état dans un réducteur

Créé le 15 avr. 2016  ·  3Commentaires  ·  Source: reduxjs/redux

Est-ce un réducteur de redux valide?

function reducer(state={ byId: {}, ids: [] }, action) {
  switch (action.type) {
    case 'ADD':
      state = { ...state }
      state.byId[action.id] = action.value
      state.ids.push(action.id)
      return state

    default:
      return state
  }
}

L'état entier est d'abord cloné superficiellement, donc un nouvel objet sera renvoyé, mais les objets internes restent les mêmes et mutés.

Ou dois-je faire quelque chose comme:

function reducer(state={ byId: {}, ids: [] }, action) {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        byId: {
          ...state.byId,
          [action.id]: action.value
        },
        ids: [ ...state.ids, action.id ]
      }

    default:
      return state
  }
}

Les effets secondaires que je vois avec la première approche sont dans DevTools LogMonitor :

  • développer un sous-nœud (par exemple byId ) dans un état précédent affichera la même valeur que le dernier même s'il s'agissait d'autre chose auparavant
  • le voyage dans le temps ne fonctionne pas

Est-ce juste un bogue dans le LogMonitor ou la seconde approche est-elle la bonne ? Si j'ajoute state = _.cloneDeep(state) avant les mutations, cela fonctionne bien, prouvant que le LogMonitor réutilise les mêmes objets, donc les mêmes valeurs.

Le reste de l'application fonctionne bien et les vues @connect ed se mettent à jour correctement.

Commentaire le plus utile

Ce dernier exemple est ce que vous devez faire. Évidemment, cela peut devenir un peu verbeux si vous imbriquez des choses. Il existe plusieurs bibliothèques utilitaires qui tentent de résumer cela pour vous, et j'en ai certaines répertoriées dans la page Données immuables de ma liste de bibliothèques Redux.

La composition du réducteur aide également à cela.

function byId(state = {}, action) {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        [action.id]: action.value
      }
    default:
      return state
  }
}

function ids(state = [], action) {
  switch (action.type) {
    case 'ADD':
      return [ ...state, action.id ]
    default:
      return state
  }
}

const reducer = combineReducers({
  byId,
  ids
})

Tous les 3 commentaires

Non, ce premier exemple est en train de muter absolument l'état. La copie superficielle initiale crée un nouvel objet, mais le nouvel objet pointe vers les mêmes références byId et ids que l'original. Ainsi, lorsque vous faites byId[action.id] = action.value et ids.push(action.id) , vous modifiez les éléments d'origine.

Ce dernier exemple est ce que vous devez faire. Évidemment, cela peut devenir un peu verbeux si vous imbriquez des choses. Il existe plusieurs bibliothèques utilitaires qui tentent de résumer cela pour vous, et j'en ai certaines répertoriées dans la page Données immuables de ma liste de bibliothèques Redux.

La FAQ Redux a également une question qui couvre correctement la mise à jour de l'état de manière immuable : http://redux.js.org/docs/FAQ.html#react -not-rerendering .

Ce dernier exemple est ce que vous devez faire. Évidemment, cela peut devenir un peu verbeux si vous imbriquez des choses. Il existe plusieurs bibliothèques utilitaires qui tentent de résumer cela pour vous, et j'en ai certaines répertoriées dans la page Données immuables de ma liste de bibliothèques Redux.

La composition du réducteur aide également à cela.

function byId(state = {}, action) {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        [action.id]: action.value
      }
    default:
      return state
  }
}

function ids(state = [], action) {
  switch (action.type) {
    case 'ADD':
      return [ ...state, action.id ]
    default:
      return state
  }
}

const reducer = combineReducers({
  byId,
  ids
})

@gaearon @markerikson Merci. J'ai fini par écrire un réducteur d'ordre élevé qui gère des listes indexées dynamiques (par ID)

Code : https://gist.github.com/elado/95484b754f31fcd6846c7e75de4aafe4

Cette page vous a été utile?
0 / 5 - 0 notes