web-dev-qa-db-fra.com

Mise à jour des données imbriquées dans Redux Store

Quelle est la meilleure façon/correcte de mettre à jour un tableau imbriqué de données dans un magasin en utilisant redux?

Mon magasin ressemble à ceci:

{
    items:{
        1: {
            id: 1,
            key: "value",
            links: [
                {
                    id: 10001
                    data: "some more stuff"
                },
                ...
            ]
        },
        ...
    }
}

J'ai une paire d'actions asynchrones qui met à jour l'objet complet items mais j'ai une autre paire d'actions que je souhaite mettre à jour un tableau spécifique links.

Mon réducteur ressemble actuellement à ceci, mais je ne suis pas sûr que ce soit la bonne approche:

  switch (action.type) {
    case RESOURCE_TYPE_LINK_ADD_SUCCESS:
      // TODO: check whether the following is acceptable or should we create a new one?
      state.items[action.resourceTypeId].isSourceOf.Push(action.resourceTypeLink);
      return Object.assign({}, state, {
        items: state.items,
      });
  }
47
Clarkie

React update() assistant de l'immuabilité est un moyen pratique de créer une version mise à jour d'un ancien objet JavaScript simple sans le muter.

Vous lui donnez l'objet source à mettre à jour et un objet décrivant les chemins d'accès aux pièces à mettre à jour et les modifications à apporter.

par exemple, si une action avait les propriétés id et link et que vous vouliez transférer le link dans un tableau de liens dans un élément associé au id:

var update = require('react/lib/update')

// ...

return update(state, {
  items: {
    [action.id]: {
      links: {$Push: action.link}
    }
  }
})

(Exemple utilise un nom de propriété calculé ES6 pour action.id)

50
Jonny Buchanan

La réponse de Jonny est correcte (ne modifiez jamais l'état qui vous a été attribué!) Mais je voulais ajouter un autre point. Si tous vos objets ont des ID, il est généralement déconseillé de conserver la forme de l'état imbriquée.

Cette:

{
  items: {
    1: {
      id: 1,
      links: [{
        id: 10001
      }]
    }
  }
}

est une forme difficile à mettre à jour.

Ce ne doit pas être comme ça! Vous pouvez plutôt le stocker comme ceci:

{
  items: {
    1: {
      id: 1,
      links: [10001]
    }
  },
  links: {
    10001: {
      id: 10001
    }
  }
}

C'est beaucoup plus facile pour la mise à jour car il n'y a qu'une seule copie canonique de toute entité. Si vous devez laisser l’utilisateur “éditer un lien”, il n’ya qu’un endroit où il doit être mis à jour - et il est complètement indépendant de items ou de tout autre élément faisant référence à links.

Pour obtenir vos réponses API dans une telle forme, vous pouvez utiliser normalizr . Une fois que vos entités au sein des actions du serveur sont normalisées, vous pouvez écrire un simple réducteur qui les fusionne dans l'état actuel:

import merge from 'lodash/object/merge';

function entities(state = { items: {}, links: {} }, action) {
  if (action.response && action.response.entities) {
    return merge({}, state, action.response.entities);
  }

  return state;
}

S'il vous plaît voir Redux real-world exemple pour une démonstration de cette approche.

58
Dan Abramov