Comment puis-je réinitialiser un composant de réaction, y compris tous les états accessibles de manière transitoire?

93

J'ai parfois des composants de réaction qui sont conceptuellement avec état que je souhaite réinitialiser. Le comportement idéal équivaudrait à supprimer l'ancien composant et à lire un nouveau composant vierge.

React fournit une méthode setStatequi permet de définir le propre état explicite des composants, mais qui exclut l'état implicite tel que le focus du navigateur et l'état du formulaire, et il exclut également l'état de ses enfants. Attraper tout cet état indirect peut être une tâche délicate, et je préférerais le résoudre de manière rigoureuse et complète plutôt que de jouer à un coup de taupe avec chaque nouvel état surprenant.

Existe-t-il une API ou un modèle pour faire cela?

Edit: J'ai fait un exemple trivial démontrant l' this.replaceState(this.getInitialState())approche et la contrastant avec l' this.setState(this.getInitialState())approche: jsfiddle - replaceStateest plus robuste.

Eamon Nerbonne
la source

Réponses:

206

Pour vous assurer que l'état implicite du navigateur que vous mentionnez et l'état des enfants sont réinitialisés, vous pouvez ajouter un keyattribut au composant de niveau racine renvoyé par render; quand il change, ce composant sera jeté et créé à partir de zéro.

render: function() {
    // ...
    return <div key={uniqueId}>
        {children}
    </div>;
}

Il n'y a pas de raccourci pour réinitialiser l'état local du composant individuel.

Sophie Alpert
la source
1
Juste par curiosité, quand vous dites `` le composant sera jeté et créé à partir de zéro '', voulez-vous dire que le DOM virtuel sera jeté et créé à partir de zéro mais que les mises à jour du DOM se produiront toujours en fonction de l'algorithme de différence?
nimgrg
1
@nimgrg Non, les vrais éléments du DOM seront également recréés. (Le DOM virtuel est déjà recréé sur chaque rendu, donc si vous voulez conserver le vrai DOM, ne définissez simplement pas de keydans ce cas.)
Sophie Alpert
3
@EamonNerbonne Sur React 0.8, les clés ne sont utilisées que pour distinguer les éléments frères d'un tableau et ont été ignorées à la racine. Voir github.com/facebook/react/issues/590 .
Sophie Alpert
Notez replaceState()et getInitialState()sont tous deux obsolètes dans les nouveaux reactjs de style classe ES6. Utilisez this.setState(this._getInitialState())plutôt. De plus, vous ne pouvez pas nommer votre propre fonction d'initialisation d'état getInitialState()- react jette un avertissement - appelez-la autrement et faites-le explicitement state = this._getInitialState()au niveau supérieur de la classe.
thom_nic
2
Existe-t-il un moyen de le faire de l'intérieur d'un composant sans avoir besoin de l'extérieur pour passer un accessoire clé?
trusktr
14

Vous devriez en fait éviter replaceStateet utiliser à la setStateplace.

La documentation indique que replaceState"peut être entièrement supprimé dans une future version de React". Je pense qu'il sera très certainement supprimé car replaceStatene correspond pas vraiment à la philosophie de React. Cela facilite le fait qu'un composant React commence à se sentir un peu comme un couteau suisse. Cela empêche la croissance naturelle d'un composant React de devenir plus petit et plus conçu à cet effet.

Dans React, si vous devez vous tromper sur la généralisation ou la spécialisation: visez la spécialisation. En corollaire, l'arborescence des états de votre composant doit avoir une certaine parcimonie (c'est bien d'enfreindre cette règle avec goût si vous échafaudez un nouveau produit de marque).

Quoi qu'il en soit, c'est comme ça que vous faites. Similaire à la réponse (acceptée) de Ben ci-dessus, mais comme ceci:

this.setState(this.getInitialState());

Aussi (comme Ben l'a également dit) afin de réinitialiser "l'état du navigateur", vous devez supprimer ce nœud DOM. Exploitez la puissance du vdom et utilisez un nouvel keyaccessoire pour ce composant. Le nouveau rendu remplacera ce composant en gros.

Référence: https://facebook.github.io/react/docs/component-api.html#replacestate

wle8300
la source
2
Cela ne fonctionnera pas si l'état actuel comprend des propriétés qui ne sont pas dans l'état initial. Bien que je ne pense pas que ce soit un grand "état" des choses, à moins que vous ne puissiez l'empêcher d'une manière ou d'une autre, je voudrais éviter une casse surprenante. Je serais d'accord avec une réinitialisation qui plante dans certains cas, mais pas une réinitialisation qui corrompt subtilement l'état.
Eamon Nerbonne le
Je ne suis pas sûr de suivre. Êtes-vous en train de dire que ce n'est pas équivalent à this.replaceState? Parce que ça l'est.
wle8300 le
1
@ williamle8300 Ils ne seraient pas équivalents si une nouvelle propriété était ajoutée à l'état quelque part dans le cycle de vie du composant entre les appels à getInitialState()(par exemple, dans un gestionnaire onClick). Dans ce cas, cette nouvelle propriété serait toujours présente après le 2 getInitialState().
Graham
@Graham Je pense que c'est une mauvaise pratique d'introduire un nouvel état dans un composant qui n'est pas déjà déclaré getInitialState. Un peu comme déclarer toutes vos variables dans une fonction JS en haut de la fonction. Note latérale: la solution de Ben Alpert est presque identique à la mienne ... et c'est un mainteneur officiel de React!
wle8300
1
J'ai peur que la fonction getInitialState (), et donc la réponse, soit obsolète. Une mise à jour serait bien.
Martin R.
8

L'ajout d'un keyattribut à l'élément que vous devez réinitialiser le rechargera à chaque fois que le propsou l' stateassocié à l'élément changera.

key = {nouvelle date (). getTime ()}

Voici un exemple:

render() {
  const items = (this.props.resources) || [];
  const totalNumberOfItems = (this.props.resources.noOfItems) || 0;

  return (
    <div className="items-container">
      <PaginationContainer
        key={new Date().getTime()}
        totalNumberOfItems={totalNumberOfItems}
        items={items}
        onPageChange={this.onPageChange}
      />
    </div>
  );
}
jsbisht
la source
1
Ou vous pouvez ajouter une simple variable de compteur entier comme clé
minimaliste