3
votes

React setState pour l'objet d'état à plusieurs niveaux

J'essaye de mettre à jour mon objet d'état qui contient plusieurs niveaux. Consultez cet exemple https://codesandbox.io/s/oq9kp9vy5y .

Le problème est que les valeurs de la méthode de rendu ne se mettent pas à jour ... seulement la première. Puis-je forcer une mise à jour ou y a-t-il un meilleur moyen?

Merci Kasper


8 commentaires

Vous devez inclure des extraits de code pertinents plutôt qu'un simple lien, car le lien pourrait se rompre.


Pourquoi définissez-vous l'état dans componentDidMount () ? Pourquoi ne pas simplement être votre état initial?


Vous mettez à jour une valeur (state.kitchen) et en restituez une autre (state.calcuatedUsage.kitchen).


En fait, je trouve le lien codesandbox très utile. Cela m'a beaucoup aidé à déboguer.


@ShaneCavaliere "S'il est possible de créer un exemple en direct du problème auquel vous pouvez créer un lien (par exemple, sur sqlfiddle.com < / a> ou jsbin.com ) puis faites-le - mais incluez également le code dans votre question elle-même. Tout le monde ne peut pas accéder à des sites externes et les liens peuvent se rompre avec le temps. " - stackoverflow.com/help/how-to-ask


Assez juste, bon point :)


@Galupuf, la prochaine fois que j'inclurai le code pertinent, merci pour les directives. La raison pour laquelle je mets à jour mon objet d'état dans componentDidMount () est uniquement pour donner un exemple simple.


@ShaneCavaliere, merci je suis d'accord avec vous :)


3 Réponses :


2
votes

Essayez quelque chose comme ceci

import React, { Component } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      caclulatedUsage: {
        bath: 0,
        kitchen: {
          stove: 0,
          fridge: 0,
          dishwasher: 0
        },
        livingroom: {
          tv: 0,
          tvBox: 0
        }
      }
    };
  }

  componentDidMount() {
    this.setState(
      {
        caclulatedUsage: Object.assign({}, this.state.access, {
          caclulatedUsage: {
            ...this.state.caclulatedUsage,
            bath: 12
          },
          kitchen: {
            ...this.state.caclulatedUsage.kitchen,
            stove: 14,
            fridge: 23,
            dishwasher: 34
          }
        })
      },
      () => {
        console.log(this.state);
      }
    );
  }

  render() {
    return (
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        {this.state.caclulatedUsage.bath}
        <br />
        {this.state.caclulatedUsage.kitchen.stove}
        <br />
        {this.state.caclulatedUsage.kitchen.fridge}
        <br />
        {this.state.caclulatedUsage.kitchen.dishwasher}
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);


2 commentaires

Cela devrait être le bon Ne jamais muter cet état. Traitez cet état comme s'il était immuable. Mais quel est le point de définir l'état dans componentDidMount ()?


Cet exemple accède à this.state à l'intérieur de l'appel this.setState , ce qui n'est pas une bonne idée. Si vous devez accéder à l'état précédent pendant la mise à jour, vous devez utiliser la version fonctionnelle de this.setState .



0
votes

Essayez :

  componentDidMount() {
    this.setState(
      {
        caclulatedUsage: {
          ...this.state.caclulatedUsage,
          bath: 12,
           kitchen: {
               ...this.state.caclulatedUsage.kitchen,
               stove: 14,
               fridge: 23,
               dishwasher: 34
           }
        }

      }
      () => {
        console.log(this.state);
      }
    );
  }


1 commentaires

Cet exemple accède à this.state à l'intérieur de l'appel this.setState , ce qui n'est pas une bonne idée. Si vous devez accéder à l'état précédent pendant la mise à jour, vous devez utiliser la version fonctionnelle de this.setState .



5
votes

Dans votre état initial, vous avez l'objet cuisine à l'intérieur de l'objet calculéUsage . Mais dans votre appel setState , vous avez l'objet cuisine en dehors de calculUsage .

De plus, lorsque vous accèdent à l'état précédent dans setState , il est préférable d'utiliser la version fonctionnelle de setState , par exemple:

componentDidMount() {
  this.setState(
    prevState => ({
      caclulatedUsage: {
        ...prevState.caclulatedUsage,
        bath: 12,
        kitchen: {
          ...prevState.caclulatedUsage.kitchen,
          stove: 14,
          fridge: 23,
          dishwasher: 34
        }
      }
    }),
    () => {
      console.log(this.state);
    }
  );
}

Le La raison en est que setState peut être asynchrone, ce qui signifie qu'accéder à this.state ne peut pas vous donner la valeur que vous attendez. L'utilisation de la version fonctionnelle pour les changements d'état transactionnel garantit des résultats cohérents.

Vous pouvez également consulter le immer la bibliothèque. Cela facilite grandement la mise à jour de l'état profondément imbriqué, en vous permettant d'effectuer des mises à jour immuables avec une API mutable. Voici une fourchette de votre exemple de codesandbox qui utilise immer: https://codesandbox.io/s/180p7p0o84


1 commentaires

... et Immer a fière allure, je vais essayer.