Reagisci Casella di controllo che non invia onChange


136

TLDR: utilizzare defaultChecked anziché jsbin funzionante e controllato .

Tentativo di impostare una semplice casella di controllo che barrerà il testo dell'etichetta quando è selezionata. Per qualche motivo handleChange non viene attivato quando utilizzo il componente. Qualcuno può spiegare cosa sto facendo di sbagliato?

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

Uso:

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

Soluzione:

L'uso di controllato non consente il cambiamento del valore sottostante (apparentemente) e quindi non chiama il gestore onChange. Il passaggio a defaultChecked sembra risolvere questo problema:

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

3
Prima di tutto, perché non aggiungere un onChange che sia più semplice this.setState({checked: !this.state.checked})che dover memorizzare un valore. Quindi un operatore ternario nell'attubato controllato:checked={this.state.checked ? 'checked': null}
— zackify il

È così che è iniziato, ma non è mai sembrato aggiornarsi. Così ho iniziato a fluffare qua e là per eseguire il debug di ciò che non veniva licenziato. Idealmente tornerà alla forma più semplice una volta completato :)
— jdarling

Supponendo che mountNode sia un vero nodo dom, dovresti usarlo this.refs.complete.getDOMNode().checked. vedi violino jsfiddle.net/d10xyqu1
— trekforever,

Può solo usare state invece di ottenere il nodo dom però: jsfiddle.net/d10xyqu1/1 Funziona bene, devi aver sbagliato a digitare qualcosa.
— Zackify,

2
Ignora il commento TLDR - defaultChecked non è sempre la risposta
— Chris

Risposte:


207

Per ottenere lo stato selezionato della casella di controllo, il percorso sarebbe:

this.refs.complete.state.checked

L'alternativa è ottenerlo dall'evento passato nel handleChangemetodo:

event.target.checked

3
handleChange non viene mai chiamato, non importa se si fa clic sulla casella o sull'etichetta, handleChange non viene chiamato :(.
— jdarling

13
Prova a utilizzare defaultChecked = {this.state.complete} anziché "controllato" sul tuo input.
— zbyte,

Questo è tutto ... cercato per sempre guardando e frugando in giro. Aggiornerà la domanda con una risposta operativa completa nel caso in cui anche altri lo incontrino.
— jdarling

Ma perché - avere lo stesso problema ma dovresti usarlo checkedper componenti controllati: /
— Dominic

4
impostazione checkedsignifica che lo stato è gestito al di fuori del componente. Quando l'utente fa clic, non c'è nulla da chiamare handleChangepoiché nessuno stato viene aggiornato. Invece dovresti ascoltare onClicke attivare un aggiornamento di stato lì.
— Zbyte,

29

In questi casi è meglio non usare i riferimenti. Uso:

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

Ci sono alcune opzioni:

checked vs defaultChecked

Il primo rispondeva sia ai cambiamenti di stato che ai clic. Quest'ultimo ignorerebbe i cambiamenti di stato.

onClick vs onChange

Il primo si attiverà sempre sui clic. Quest'ultimo non si attiverebbe ai clic se l' checkedattributo è presente inputsull'elemento.


10

Nello scenario NON si desidera utilizzare il gestore onChange sul DOM di input, è possibile utilizzare la onClickproprietà in alternativa. La defaultCheckedcondizione può lasciare uno stato fisso per I16M v16.

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

Spero che questo aiuti qualcuno in futuro.


10

Se hai una handleChangefunzione simile a questa:

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

È possibile creare una onChangefunzione personalizzata in modo che si comporti come un input di testo:

<input
  type="checkbox"
  name="check"
  checked={this.state.check}
  onChange={(e) => {
    this.handleChange({
      target: {
        name: e.target.name,
        value: e.target.checked,
      },
    });
  }}
/>

non è handleChangeacceso inputdovrebbe essere this.handleChange?
— Ardhi,

5

Nel caso in cui qualcuno stia cercando un gestore di eventi universale, è possibile utilizzare più o meno il seguente codice (supponendo che la proprietà name sia impostata per ogni input):

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

2

onChange non chiamerà handleChange su dispositivo mobile quando si utilizza defaultChecked. In alternativa puoi usare onClick e onTouchEnd.

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

1

Nell'interfaccia utente materiale, lo stato della casella di controllo può essere recuperato come

this.refs.complete.state.switched
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.