web-dev-qa-db-fra.com

Remplacer l'objet dans le tableau à l'état de réaction

Cette question pourrait tomber un peu du côté d'une question de "meilleure pratique", mais s'il vous plaît, continuez avec moi.

Voici une partie de mon état:

this.state = {
  typeElements: {
    headers: [
        {
          name: "h1",
          size: 70,
          lineHeight: 1.25,
          kearning: 0,
          marginAfter: 0
        }, {
          name: "h2",
          size: 70,
          lineHeight: 1.25,
          kearning: 0,
          marginAfter: 0
        }, {
          name: "h3",
          size: 70,
          lineHeight: 1.25,
          kearning: 0,
          marginAfter: 0
        }...

Ce que je dois faire est de remplacer l'objet à un index donné sur le tableau d'en-têtes.

Je ne sais pas comment faire cela avec la méthode setState comme dans this.setState(headers[1] = {obj}) - mais c'est évidemment invalide. Ma méthode actuelle consiste à créer un nouveau tableau et à supprimer l'ancien comme ceci:

_updateStyle(props) {
  let newState = Object.assign({}, this.state)
  newState.typeElements.headers[props.index] = props
  this.setState(newState)
};

Pour mon petit projet de hacky, je suppose que tout va bien, mais j’ai l’impression que ce projet est très lourd et que cela entraînerait rapidement des problèmes de performances à n’importe quel niveau.

7
motleydev

Mise à jour: comme cette réponse reçoit toujours des votes positifs, sachez que la réponse précédente ci-dessous est obsolète avec JavaScript moderne et React. L'addon "update" est maintenant hérité et "immutability-helper" peut être utilisé à la place.

Les documents React expliquent également pourquoi l’immutabilité est importante , évitez donc les mutations. Pour les mises à jour immuables, vous pouvez utiliser la syntaxe Object.assign() ou spread qui doit être effectuée pour chaque niveau d'imbrication, comme dans cet exemple, l'objet imbriqué headers et ses éléments de tableau. Dans cet exemple particulier, nous pouvons utiliser l'index de tableau comme clé afin de pouvoir également utiliser l'opérateur spread pour créer un clone superficiel du tableau et affecter un nouvel objet comme valeur à un index donné dans le tableau cloné.

_updateStyle (props) {
  const { typeElements } = this.state;
  const updatedHeaders = [...typeElements.headers];
  updatedHeaders[props.index] = props;
  this.setState({
    ...this.state,
    typeElements: {
      ...typeElements,
      headers: updatedHeaders
    }
  ));
}

Une autre solution qui ne nécessite pas la syntaxe de propagation et qui est nécessaire si nous n’utilisons pas l’index de tableau pour trouver l’objet à remplacer, utilise array.map pour créer un nouveau tableau et renvoie le nouvel objet à la place de l’ancien. indice.

  const updatedHeaders = typeElements.headers.map((obj, index) => {
    return index === props.index ? props : obj;
  });

Des exemples similaires dans la documentation Redux expliquent également "modèles de mise à jour immuables" .

React a quelques aides d’immuabilité pour cela, ce qui est expliqué dans les docs: https://facebook.github.io/react/docs/update.html

Dans votre cas, vous pouvez utiliser la commande $ splice pour supprimer un élément et ajoutez le nouveau à l'index donné, par exemple:

_updateStyle (props) {
  this.setState(update(this.state.typeElements, 
    { $splice: [[props.index, 1, props]] }
  ));
}
11
Robin Venneman

utiliser immutability-helper

vous pouvez y trouver de beaux exemples

1
ChaosPredictor

Offrant une meilleure explication sur la façon de procéder.

  • Tout d'abord, recherchez l'index de l'élément que vous remplacez dans le tableau d'état.
  • Deuxièmement, update l'élément à cet index
  • Troisièmement, appelez setState avec la nouvelle collection
import update from 'immutability-helper';

// this.state = { employees: [{id: 1, name: 'Obama'}, {id: 2, name: 'Trump'}] } 

updateEmployee(employee) {
    const index = this.state.employees.findIndex((emp) => emp.id === employee.id);
    const updatedEmployees = update(this.state.employees, {$splice: [[index, 1, employee]]});  // array.splice(start, deleteCount, item1)
    this.setState({employees: updatedEmployees});
}
0
daino3

J'ai eu ton idée. Autant que je sache, la méthode setState() ne peut pas changer le contenu enfant du tableau. Alors utilisez plutôt cette méthode, modifiez-la directement.

this.state.typeElements.headers[theIndex] = value;

mais, en le modifiant directement, le composant ne sera pas rendu de nouveau. Vous pouvez le forcer à effectuer un nouveau rendu avec cette méthode.

this.forceUpdate()

remarque: mais attention, cette pratique est considérée comme mauvaise, vous devez vous assurer que votre état est immuable. Ici référence de tableau immuable

0

Object.Assign utilise une copie superficielle, pas une copie complète. 

Sachez que, dans votre exemple, Object.assign({}, this.state) copie uniquement les liens vers les enfants les plus proches du tableau state, c’est-à-dire typeElements, mais le tableau headers n’est pas copié.

Il y a un sucre syntaxique ... dans ES6 pour Object.Assign, Babel a l'addon spécial transform-object-rest-spread

let newHeaders = { ...this.state.typeElements.headers};
newHeaders[index] = props.Something;

let newState = {...state, typeElements: { newHeaders }};
0
Artru