Reagieren Sie das Kontrollkästchen, das onChange nicht sendet

136

TLDR: Verwenden Sie defaultChecked anstelle von aktiviertem , funktionierendem jsbin .

Es wird versucht, ein einfaches Kontrollkästchen einzurichten, bei dem der Beschriftungstext durchgestrichen wird, wenn es aktiviert ist. Aus irgendeinem Grund wird handleChange nicht ausgelöst, wenn ich die Komponente verwende. Kann mir jemand erklären, was ich falsch mache?

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>
    );
  }
});

Verwendung:

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

Lösung:

Durch die Verwendung von "Check" wird der zugrunde liegende Wert (anscheinend) nicht geändert, und der onChange-Handler wird nicht aufgerufen. Das Wechseln zu defaultChecked scheint dies zu beheben:

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>
    );
  }
});
jdarling
quelle
3
Fügen Sie zunächst einen onChange hinzu, der this.setState({checked: !this.state.checked})einfacher ist als das Speichern eines Werts. Dann ein ternärer Operator im geprüften Attribut:checked={this.state.checked ? 'checked': null}
Zackify
So fing es an, aber es schien nie zu aktualisieren. Also fing ich an, es hier und da zu fusseln, um zu debuggen, was nicht abgefeuert wurde. Idealerweise
kehren Sie
Angenommen, Ihr mountNode ist ein tatsächlicher dom-Knoten, müssten Sie verwenden this.refs.complete.getDOMNode().checked. siehe fiddle jsfiddle.net/d10xyqu1
trekforever
Er kann jedoch nur state verwenden, anstatt den dom-Knoten abzurufen : jsfiddle.net/d10xyqu1/1 Es funktioniert einwandfrei , Sie müssen etwas falsch eingegeben haben.
Zackify
2
Ignorieren Sie den TLDR-Kommentar - defaultChecked ist nicht immer die Antwort
Chris

Antworten:

207

Um den aktivierten Status Ihres Kontrollkästchens zu erhalten, lautet der Pfad wie folgt:

this.refs.complete.state.checked

Die Alternative besteht darin, es von dem an die handleChangeMethode übergebenen Ereignis abzurufen :

event.target.checked
zbyte
quelle
3
handleChange wird nie aufgerufen, egal ob Sie auf das Kontrollkästchen oder die Beschriftung klicken, handleChange wird nicht aufgerufen :(.
jdarling
13
Versuchen Sie, defaultChecked = {this.state.complete} anstelle von "checked" für Ihre Eingabe zu verwenden.
Zbyte
Das war es ... Ich habe immer gesucht und mich umgesehen. Aktualisiert die Frage mit der vollständigen Antwort, falls andere auch darauf stoßen.
Jdarling
Aber warum - mit dem gleichen Problem, aber Sie sollten checkedfür kontrollierte Komponenten verwenden: /
Dominic
4
Einstellung checkedbedeutet, dass der Status außerhalb der Komponente verwaltet wird. Wenn der Benutzer auf klickt, kann nichts aufgerufen werden, handleChangeda kein Status aktualisiert wird. Stattdessen müssten Sie dort auf eine Statusaktualisierung warten onClickund diese auslösen.
Zbyte
29

In solchen Fällen ist es besser, keine Refs zu verwenden. Verwenden:

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

Es gibt einige Optionen:

checked vs. defaultChecked

Ersteres würde sowohl auf Statusänderungen als auch auf Klicks reagieren . Letzteres würde Zustandsänderungen ignorieren.

onClick vs. onChange

Ersteres würde immer bei Klicks ausgelöst. Letzteres würde bei Klicks nicht ausgelöst, wenn das checkedAttribut für das inputElement vorhanden ist.

Lin
quelle
10

In dem Szenario, in dem Sie den onChange-Handler NICHT für das Eingabe-DOM verwenden möchten, können Sie die onClickEigenschaft alternativ verwenden. Die defaultCheckedBedingung kann einen festen Zustand für v16 IINM hinterlassen.

 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>
        )
    }
 }

Ich hoffe das hilft jemandem in der Zukunft.

akiespenc
quelle
10

Wenn Sie eine handleChangeFunktion haben, die so aussieht:

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

Sie können eine benutzerdefinierte onChangeFunktion so erstellen , dass sie sich wie eine Texteingabe verhält:

<input
  type="checkbox"
  name="check"
  checked={this.state.check}
  onChange={(e) => {
    this.handleChange({
      target: {
        name: e.target.name,
        value: e.target.checked,
      },
    });
  }}
/>
spencer.sm
quelle
ist nicht handleChangeauf inputsollte sein this.handleChange?
Ardhi
5

Falls jemand für einen universellen Event - Handler kann der folgende Code mehr oder weniger verwendet werden (unter der Annahme , dass Name - Eigenschaft wird für jeden Eingang eingestellt):

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

onChange ruft handleChange auf Mobilgeräten nicht auf, wenn defaultChecked verwendet wird. Alternativ können Sie onClick und onTouchEnd verwenden.

<input onClick={this.handleChange} onTouchEnd={this.handleChange} type="checkbox" defaultChecked={!!this.state.complete} />;
Gerber Burton
quelle
1

In der Material-Benutzeroberfläche kann der Status des Kontrollkästchens als abgerufen werden

this.refs.complete.state.switched
Sakshi Nagpal
quelle