React Pole wyboru nie wysyła przy zmianie

141

TLDR: Użyj defaultChecked zamiast sprawdzonego, działającego jsbin .

Próbuję ustawić proste pole wyboru, które przekreśli tekst swojej etykiety, gdy jest zaznaczone. Z jakiegoś powodu handleChange nie odpala, gdy używam komponentu. Czy ktoś może wyjaśnić, co robię źle?

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

Stosowanie:

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

Rozwiązanie:

Korzystanie z zaznaczonego nie pozwala na zmianę wartości bazowej (najwyraźniej), a zatem nie wywołuje procedury obsługi onChange. Przełączanie na domyślne ustawienie Checked wydaje się rozwiązać ten problem:

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
źródło
3
Po pierwsze, dlaczego nie dodać onChange, który jest this.setState({checked: !this.state.checked})prostszy niż konieczność przechowywania wartości. Następnie operator trójskładnikowy w sprawdzonym attrubute:checked={this.state.checked ? 'checked': null}
zackify
Tak to się zaczęło, ale nigdy nie wydawało się aktualizować. Więc zacząłem go tu i tam rozwalać, aby debugować to, co nie zostało zwolnione. Idealnie wrócę do najprostszej formy po wypełnieniu :)
jdarling
Zakładając, że twój mountNode jest rzeczywistym węzłem dom, musiałbyś użyć this.refs.complete.getDOMNode().checked. zobacz fiddle jsfiddle.net/d10xyqu1
trekforever
Może jednak po prostu użyć state zamiast uzyskać węzeł dom: jsfiddle.net/d10xyqu1/1 Działa dobrze, musisz coś źle wpisać.
zackify
2
Zignoruj ​​komentarz TLDR - defaultChecked nie zawsze jest odpowiedzią
Chris

Odpowiedzi:

216

Aby uzyskać stan zaznaczenia pola wyboru, ścieżka będzie wyglądać następująco:

this.refs.complete.state.checked

Alternatywą jest pobranie go ze zdarzenia przekazanego do handleChangemetody:

event.target.checked
zbyte
źródło
5
handleChange nigdy nie jest wywoływany, nie ma znaczenia, czy klikniesz pole wyboru czy etykietę, handleChange nie zostanie wywołany :(.
jdarling
14
Spróbuj użyć defaultChecked = {this.state.complete} zamiast „zaznaczone” w swoich danych wejściowych.
zbyte
To było to ... Przeszukiwane wiecznie, szukając i grzebując. Zaktualizuje pytanie z pełną działającą odpowiedzią na wypadek, gdyby inni też na to natknęli.
jdarling
Ale dlaczego - mam ten sam problem, ale powinieneś używać checkeddo kontrolowanych komponentów: /
Dominic
4
ustawienie checkedoznacza, że ​​stan jest zarządzany poza komponentem. Gdy użytkownik kliknie, nie ma nic do wywołania, handleChangeponieważ żaden stan nie jest aktualizowany. Zamiast tego musiałbyś nasłuchiwać onClicki wyzwalać tam aktualizację stanu.
zbyte
31

W takich przypadkach lepiej nie używać referencji. Posługiwać się:

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

Jest kilka opcji:

checked vs defaultChecked

Ten pierwszy reagowałby zarówno na zmiany stanu, jak i na kliknięcia. Ten ostatni ignorowałby zmiany stanu.

onClick vs onChange

Ta pierwsza zawsze wywoływała kliknięcia. Ta ostatnia nie wywoła kliknięć, jeśli checkedatrybut jest obecny w inputelemencie.

Lin
źródło
Używam React 16.13.1 i nie możesz podać sprawdzonej właściwości bez właściwości onChange. Jeśli zdefiniuję oba i sprawię, że zaznaczona właściwość będzie reagować na dane wejściowe, otrzymam żądane zachowanie i wyzwalacze onChange za każdym razem, gdy kliknę to pole. Myślę więc, że ta odpowiedź stała się nieaktualna.
Ian
12

W scenariuszu, w którym NIE chciałbyś używać procedury obsługi onChange na wejściowym DOM, możesz użyć tej onClickwłaściwości jako alternatywy. defaultChecked, Warunek może opuścić stan ustalony dla v16 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>
        )
    }
 }

Mam nadzieję, że to pomoże komuś w przyszłości.

akiespenc
źródło
10

Jeśli masz handleChangefunkcję, która wygląda tak:

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

Możesz utworzyć funkcję niestandardową, onChangetak aby działała jak wprowadzanie tekstu:

<input
  type="checkbox"
  name="check"
  checked={this.state.check}
  onChange={(e) => {
    this.handleChange({
      target: {
        name: e.target.name,
        value: e.target.checked,
      },
    });
  }}
/>
spencer.sm
źródło
nie jest handleChangewłączone, inputpowinno być this.handleChange?
Ardhi
6

W przypadku, gdy ktoś szuka uniwersalnej obsługi zdarzeń, można użyć mniej więcej następującego kodu (zakładając, że właściwość name jest ustawiona dla każdego wejścia):

    this.handleInputChange = (e) => {
        item[e.target.name] = e.target.type === "checkbox" ? e.target.checked : e.target.value;
    }
Paweł Gorczyński
źródło
2

onChange nie wywoła handleChange na telefonie komórkowym podczas korzystania z defaultChecked. Alternatywnie możesz użyć onClick i onTouchEnd.

<input onClick={this.handleChange} onTouchEnd={this.handleChange} type="checkbox" defaultChecked={!!this.state.complete} />;
tanner burton
źródło
1

W materialnym interfejsie użytkownika stan pola wyboru można pobrać jako

this.refs.complete.state.switched
Sakshi Nagpal
źródło