web-dev-qa-db-fra.com

Quand utiliser setState fonctionnel

J'ai appris React au cours des derniers jours, en regardant quelques tutoriels et explications concernant les différentes façons d'écrire différents éléments. Cependant, il y en a un qui m'a le plus intéressé - la fonction setState pour mettre à jour/remplacer les propriétés state d'un composant.

Par exemple, imaginez que j'ai une classe avec les éléments suivants:

class Photos extends React.Component {
    constructor() {
        super()
        state = {
            pictures: []
        }
    }

   componentDidMount() {
      // This is where the fetch and setState will occur (see below)
   }

    render() {
       return {
          <div className="container">
             {this.state.pictures}
          </div>
       }
    }
}

Cet exemple me voit récupérer des images à partir d'une API.

Étant donné que j'ai effectué mes recherches, mappages et retours pour cette fonction, je mettrai à jour le tableau d'état pictures: [] Avec les résultats obtenus lors de l'appel de l'API.

Ma question découle des différentes méthodes que j'ai vues concernant la façon de mettre à jour/remplacer la propriété d'état des images.

Je l'ai vu écrit de 2 manières différentes:

1) Cela semble être une méthode très simple et facile à lire

this.setState({pictures: pics})

2) C'est plus complexe mais je l'ai vu décrit comme une méthode plus sûre

this.setState(prevState => ({
   pictures: prevState.pictures.concat(pics)
}))

Quelqu'un pourrait-il expliquer les mérites de l'utilisation de l'un ou l'autre? Je veux être cohérent avec le code à l'avenir, traitant des accessoires et des états, etc., donc la méthode la plus polyvalente serait bien sûr préférée.

20
physicsboy

Tout d'abord, dans votre cas, les deux syntaxes sont entièrement différentes, ce que vous cherchez peut-être est la différence entre

this.setState({pictures: this.state.picture.concat(pics)})

et

this.setState(prevState => ({
   pictures: prevState.pictures.concat(pics)
}))

Pour comprendre pourquoi la deuxième méthode est préférée, vous devez comprendre ce que React fait avec setState en interne.

React fusionnera d'abord l'objet que vous avez passé à setState() dans l'état actuel. Ensuite, il commencera cette réconciliation. En raison de l'appel, setState() peut ne pas mettre à jour immédiatement votre état.

React peut regrouper plusieurs appels setState() en une seule mise à jour pour de meilleures performances.

Considérez le cas simple, pour comprendre cela, dans votre fonction, vous pouvez appeler setState plusieurs fois comme

myFunction = () => {

   ...
   this.setState({pictures: this.state.picture.concat(pics1)})
   this.setState({pictures: this.state.picture.concat(pics1)})
   this.setState({pictures: this.state.picture.concat(pics1)})

   ...
}

ce qui n'est pas un cas d'utilisation valide dans une application simple, mais comme l'application devient complexe, plusieurs appels setState peuvent se produire à partir de plusieurs endroits, faisant la même chose.

Alors maintenant, pour effectuer une mise à jour efficace, React fait le batching en extrayant tous les objets passés à chaque setState() appel, les fusionne pour former un seul objet, puis utilise cet objet unique pour faire setState(). Selon la documentation setState

Si vous essayez d'incrémenter une quantité d'article plus d'une fois dans le même cycle, cela donnera l'équivalent de:

Object.assign(
  previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ...
)

Les appels suivants remplaceront les valeurs des appels précédents dans le même cycle, donc la quantité ne sera incrémentée qu'une seule fois. Si l'état suivant dépend de l'état précédent, nous vous recommandons d'utiliser le formulaire de fonction de mise à jour, à la place

Donc, si l'un des objets contient la même clé, la valeur de la clé du dernier objet avec la même clé est stockée. Et donc la mise à jour ne se produit qu'une seule fois avec la dernière valeur

Codes de démonstration et boîte

22
Shubham Khatri

TL; DR: Fonctionnel setState est principalement utile pour s'attendre à une mise à jour d'état correcte lorsque plusieurs setState s sont déclenchés dans un court intervalle de temps où, comme conventionnel, setState effectue une réconciliation et peut conduire à un état inattendu.

Veuillez consulter ce merveilleux article sur setState fonctionnel pour bien comprendre

Et voici la DEMO DE TRAVAIL

Premièrement, vous essayez de faire des choses différentes dans chacun de vos cas, vous assignez des photos dans une et concaténez des photos dans une autre.

Disons que this.state.pictures contient [1, 2, 3] Et les photos contiennent [4, 5, 6]

this.setState({pictures: pics})

Dans le cas ci-dessus, this.state.pictures contiendra les images, c'est-à-dire this.state.pictures = [4, 5, 6]

this.setState(prevState => ({
   pictures: prevState.pictures.concat(pics)
}))

Alors que dans l'extrait ci-dessus, this.state.pictures contiendra les images + photos précédentes, c'est-à-dire this.state.pictures = [1, 2, 3, 4, 5, 6]

Quoi qu'il en soit, vous pouvez l'ajuster pour répondre aux besoins de votre API, si c'est comme une réponse paginée, vous feriez mieux de concaténer les résultats sur chaque demande, sinon si vous obtenez le tableau entier à chaque fois, attribuez simplement le tableau entier.

setState conventionnel VS setState fonctionnel

Maintenant, votre question est principalement de savoir si vous devez utiliser setState avec un objet ou avec une fonction.

Les gens les utilisent tous les deux pour différentes raisons, maintenant le setState fonctionnel est dit sûr car React fait quelque chose appelé un processus de réconciliation où il fusionne plusieurs objets à l'intérieur de setState lorsque déclenché fréquemment ou simultanément et applique les modifications en une seule fois, un peu comme un processus par lots. Cela pourrait potentiellement conduire à des résultats inattendus dans des scénarios comme ci-dessous.

EXEMPLE:

increaseScoreBy3 () {
 this.setState({score : this.state.score + 1});
 this.setState({score : this.state.score + 1});
 this.setState({score : this.state.score + 1});
}

Comme vous vous attendez à ce que le score soit incrémenté de 3 mais ce que React fait est de fusionner tous les objets et de mettre à jour le score une seule fois, c'est-à-dire en l'incrémentant de 1

C'est l'un des cas où le rappel fonctionnel brille car la réconciliation ne se produit pas sur les fonctions et l'exécution du code ci-dessous fera les choses comme prévu, c'est-à-dire mettre à jour le score de 3

increaseScoreBy3 () {
 this.setState(prevState => ({ score: prevState.score + 1 }));
 this.setState(prevState => ({ score: prevState.score + 1 }));
 this.setState(prevState => ({ score: prevState.score + 1 }));
}
8
Nandu Kalidindi

Une réponse rapide:

tilisez toujours la forme fonctionnelle de setState ().

this.setState((state, props)=>({
    someValue: state.somevalue + 1
}));

Cette approche est moins sujette aux erreurs et aide à éliminer certains bogues très difficiles à trouver. Même si react regroupe plusieurs de ces mises à jour, chaque mise à jour est un appel de fonction distinct et les mises à jour suivantes n'entraîneront pas la perte de certaines de ces mises à jour.

L'autre approche

this.setState({
someValue: state.somevalue + 1
});

S'il est répété fréquemment, peut entraîner la perte de certaines des mises à jour, car React regroupe ces mises à jour fréquentes.

1
Nitin Jadhav