web-dev-qa-db-fra.com

Définir une propriété "check" dans React

J'ai un problème très ennuyant avec React et les cases à cocher. L'application avec laquelle je travaille nécessite une liste de cases à cocher représentant les paramètres conservés dans le back-end. Il existe une option pour restaurer les paramètres à leur état d'origine .

Au début, j'ai créé un composant qui a un objet comme une carte de paramètres. Chaque paramètre a une clé et une valeur booléenne. Par conséquent:

{
    bubbles: true,
    gregory: false
}

Doit être représenté comme:

<input type="checkbox" value="bubbles" checked="checked" />
<input type="checkbox" value="gregory" />

Il semble maintenant que React ignore comment une case à cocher est censée fonctionner. Je ne veux pas définir les valeurs des cases à cocher, je veux la propriété "cochée".

Pourtant, si j'essaie quelque chose comme ça:

<input
    type="checkbox"
    value={setting}
    checked={this.settings[setting]}
    onChange={this.onChangeAction.bind(this)}
/>

Je reçois cet avertissement:

Avertissement: AwesomeComponent modifie une case à cocher de type non contrôlée à contrôler. Les éléments d'entrée ne doivent pas basculer de non contrôlés à contrôlés (ou vice versa). Choisissez d'utiliser un élément d'entrée contrôlé ou non contrôlé pour la durée de vie du composant. Plus d'infos: [des pages de documentation inutiles que j'ai lues plusieurs fois sans résultat]

J'ai donc décidé de créer un autre composant pour envelopper chaque case et j'ai obtenu ceci:

<input
    type="checkbox"
    checked={this.state.checked}
    onChange={this.onChangeAction.bind(this)}
/>

Maintenant, la checked est une propriété présente directement dans mon état.

Cela donne le même avertissement, alors j'ai essayé d'utiliser defaultChecked:

<input
    type="checkbox"
    defaultChecked={this.state.checked}
    onChange={this.onChangeAction.bind(this)}
/>

Cela fait disparaître l'avertissement, mais il est maintenant impossible de réinitialiser la valeur checked à celle par défaut. J'ai donc essayé de jouer avec la méthode componentWillReceiveProps. De cette façon, je suis presque sûr que mon état est correct, this.state.checked est correct et le composant est à nouveau rendu.

Et ça le fait. Mais la case à cocher reste telle qu’elle était à l’origine ... Pour l’instant, j’ai laissé cet avertissement déplorable et j’utilise checked.

Je pensais qu'il existait peut-être un moyen de forcer le nouveau rendu du composant, de sorte qu'il capture la nouvelle valeur defaultChecked et l'utilise. Mais je ne sais pas comment faire ça. Peut-être supprimer l'avertissement seulement pour ce composant? Est-ce possible? Peut-être y a-t-il autre chose à faire?

19
Apollo

Le problème se pose si vous définissez la propriété checked de votre case à cocher sur null ou undefined.

Ce sont des valeurs "faussement" dans JS, cependant React traite une valeur de null comme si la propriété n'était pas définie du tout. Étant donné que l'état par défaut d'une case à cocher est désactivé, tout fonctionnera correctement. Si vous définissez ensuite checked sur true React pense que la propriété est soudainement créée! C'est à ce moment que React estime que vous êtes passé de non contrôlé à contrôlé, puisque la propriété checked existe. 

Dans votre exemple, vous pouvez supprimer cet avertissement en remplaçant checked={this.settings[setting]} par checked={!!this.settings[setting]}. Notez le double coup (!!). Ils vont convertir null ou undefined en false (et laisser true seul), donc React enregistrera votre propriété checked avec une valeur de false et démarrera avec un composant de formulaire contrôlé.

J'ai eu ce problème aussi et j'ai aussi lu les docs sur les composants contrôlés plusieurs fois sans succès, mais j'ai finalement compris, alors j'ai pensé partager. De plus, depuis version 15.2.0 , les entrées normales sont déclenchées en définissant value, tandis que les cases à cocher sont initialisées de la manière contrôlée en définissant checked, quelle que soit leur propriété value, ce qui ajoute un peu à la confusion. 

46
amoebe

La réponse d'Amoebe est correcte, mais je pense qu'il existe une solution plus propre que la double banque (!!). Ajoutez simplement un defaultProps property avec la valeur false pour checked prop de votre composant Checkbox:

import React from 'react';

const Checkbox = ({checked}) => (
  <div>
      <input type="checkbox" checked={checked} />
  </div>
);

Checkbox.defaultProps = {
  checked: false
};

export default Checkbox;
6
Klofi

Fondamentalement, la variable defaultChecked signifie que vous ne voulez pas contrôler l'entrée - elle restitue avec cette valeur et il n'y a aucun moyen de la contrôler. De plus, value ne devrait pas être utilisé, mais plutôt checked, votre deuxième code devrait donc être correct. Et vous ne devriez pas les utiliser simultanément.

<input
    type="checkbox"
    checked={this.state.checked}
    onChange={this.onChangeAction.bind(this)}
/>

Pouvez-vous créer un petit violon avec ce comportement?

1
Bloomca

Vous pouvez affecter vos données à l'état, puis utiliser la propriété cochée associée à la case à cocher individuelle pour définir l'état comme

{   this.state.data.map(function(item, index) {
      return (

        <input type="checkbox" checked={item.value} onChange={this.handleChange.bind(this, index)}/>

      );
    }.bind(this))
    }

Exemple de données dans l'état est comme

data: [{name:'bubbles', value: true}, {name:'gregory', value: false}]

JSFIDDLE

0
Shubham Khatri