La case à cocher Réagir n'envoie pas le changement

136

TLDR: Utiliser defaultChecked au lieu de vérifier, de travail jsbin .

Essayer de configurer une simple case à cocher qui rayera le texte de son étiquette lorsqu'elle est cochée. Pour une raison quelconque, handleChange n'est pas déclenché lorsque j'utilise le composant. Quelqu'un peut-il expliquer ce que je fais mal?

var CrossoutCheckbox = React.createClass({
  getInitialState: function () {
    return {
        complete: (!!this.props.complete) || false
      };
  },
  handleChange: function(){
    console.log('handleChange', this.refs.complete.checked); // Never gets logged
    this.setState({
      complete: this.refs.complete.checked
    });
  },
  render: function(){
    var labelStyle={
      'text-decoration': this.state.complete?'line-through':''
    };
    return (
      <span>
        <label style={labelStyle}>
          <input
            type="checkbox"
            checked={this.state.complete}
            ref="complete"
            onChange={this.handleChange}
          />
          {this.props.text}
        </label>
      </span>
    );
  }
});

Usage:

React.renderComponent(CrossoutCheckbox({text: "Text Text", complete: false}), mountNode);

Solution:

L'utilisation de vérifié ne laisse pas la valeur sous-jacente changer (apparemment) et n'appelle donc pas le gestionnaire onChange. Le passage à defaultChecked semble résoudre ce problème:

var CrossoutCheckbox = React.createClass({
  getInitialState: function () {
    return {
        complete: (!!this.props.complete) || false
      };
  },
  handleChange: function(){
    this.setState({
      complete: !this.state.complete
    });
  },
  render: function(){
    var labelStyle={
      'text-decoration': this.state.complete?'line-through':''
    };
    return (
      <span>
        <label style={labelStyle}>
          <input
            type="checkbox"
            defaultChecked={this.state.complete}
            ref="complete"
            onChange={this.handleChange}
          />
          {this.props.text}
        </label>
      </span>
    );
  }
});
chérie
la source
3
Tout d'abord, pourquoi ne pas ajouter un onChange qui est this.setState({checked: !this.state.checked})plus simple que de devoir stocker une valeur. Puis un opérateur ternaire dans l'attrubute vérifié:checked={this.state.checked ? 'checked': null}
zackify
C'est comme ça que ça a commencé, mais ça n'a jamais semblé se mettre à jour. J'ai donc commencé à le faire bouffer ici et là pour déboguer ce qui n'était pas déclenché. Idéalement, je reviendrai à la forme la plus simple une fois terminé :)
jdarling
En supposant que votre mountNode est un nœud dom réel, vous devrez utiliser this.refs.complete.getDOMNode().checked. voir fiddle jsfiddle.net/d10xyqu1
trekforever
Il peut simplement utiliser state au lieu d'obtenir le nœud dom: jsfiddle.net/d10xyqu1/1 Cela fonctionne bien, vous devez avoir mal saisi quelque chose.
zackify
2
Ignorer le commentaire TLDR - defaultChecked n'est pas toujours la réponse
Chris

Réponses:

207

Pour obtenir l'état coché de votre case à cocher, le chemin serait:

this.refs.complete.state.checked

L'alternative est de l'obtenir à partir de l'événement passé dans la handleChangeméthode:

event.target.checked
zbyte
la source
3
handleChange n'est jamais appelé, peu importe si vous cliquez sur la case à cocher ou sur l'étiquette, handleChange n'est pas appelé :(.
jdarling
13
Essayez d'utiliser defaultChecked = {this.state.complete} au lieu de "coché" dans votre entrée.
zbyte
C'était ça ... Cherché pour toujours regarder et fouiller. Mettra à jour la question avec une réponse de travail complète au cas où d'autres rencontreraient cela aussi
jdarling
Mais pourquoi - ayant le même problème mais vous êtes censé utiliser checkedpour les composants contrôlés: /
Dominic
4
paramètre checkedsignifie que l'état est géré en dehors du composant. Lorsque l'utilisateur clique, il n'y a rien à appeler handleChangecar aucun état n'est mis à jour. Au lieu de cela, vous devrez écouter onClicket déclencher une mise à jour de l'état là-bas.
zbyte
29

Il vaut mieux ne pas utiliser de références dans de tels cas. Utilisation:

<input
    type="checkbox"
    checked={this.state.active}
    onClick={this.handleClick}
/>

Il existe quelques options:

checked contre defaultChecked

Le premier répondrait à la fois aux changements d'état et aux clics. Ce dernier ignorerait les changements d'état.

onClick contre onChange

Le premier se déclencherait toujours sur les clics. Ce dernier ne se déclencherait pas sur les clics si l' checkedattribut est présent sur l' inputélément.

Lin
la source
10

Dans le cas où vous ne souhaitez PAS utiliser le gestionnaire onChange sur le DOM d'entrée, vous pouvez utiliser la onClickpropriété comme alternative. Le defaultChecked, la condition peut laisser un état fixe pour la version 16 IINM.

 class CrossOutCheckbox extends Component {
      constructor(init){
          super(init);
          this.handleChange = this.handleChange.bind(this);
      }
      handleChange({target}){
          if (target.checked){
             target.removeAttribute('checked');
             target.parentNode.style.textDecoration = "";
          } else {
             target.setAttribute('checked', true);
             target.parentNode.style.textDecoration = "line-through";
          }
      }
      render(){
         return (
            <span>
              <label style={{textDecoration: this.props.complete?"line-through":""}}>
                 <input type="checkbox"
                        onClick={this.handleChange}
                        defaultChecked={this.props.complete}
                  />
              </label>
                {this.props.text}
            </span>
        )
    }
 }

J'espère que cela aidera quelqu'un à l'avenir.

akiespenc
la source
10

Si vous avez une handleChangefonction qui ressemble à ceci:

handleChange = (e) => {
  this.setState({
    [e.target.name]: e.target.value,
  });
}

Vous pouvez créer une onChangefonction personnalisée afin qu'elle agisse comme une entrée de texte:

<input
  type="checkbox"
  name="check"
  checked={this.state.check}
  onChange={(e) => {
    this.handleChange({
      target: {
        name: e.target.name,
        value: e.target.checked,
      },
    });
  }}
/>
spencer.sm
la source
n'est pas handleChangesur inputdevrait être this.handleChange?
Ardhi
5

Dans le cas où quelqu'un recherche un gestionnaire d'événements universel, le code suivant peut être utilisé plus ou moins (en supposant que la propriété name est définie pour chaque entrée):

    this.handleInputChange = (e) => {
        item[e.target.name] = e.target.type === "checkbox" ? e.target.checked : e.target.value;
    }
Pawel Gorczynski
la source
2

onChange n'appellera pas handleChange sur mobile lors de l'utilisation de defaultChecked. Vous pouvez également utiliser onClick et onTouchEnd.

<input onClick={this.handleChange} onTouchEnd={this.handleChange} type="checkbox" defaultChecked={!!this.state.complete} />;
tanneur burton
la source
1

Dans le matériel ui, l'état de la case à cocher peut être récupéré comme

this.refs.complete.state.switched
Sakshi Nagpal
la source