Флажок React не отправляет onChange


137

TL; DR: используйте defaultChecked вместо отмеченного рабочего jsbin .

Попытка установить простой флажок, который будет перечеркивать его текст метки, когда он установлен. По какой-то причине handleChange не запускается, когда я использую компонент. Может кто-нибудь объяснить, что я делаю не так?

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

Использование:

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

Решение:

Использование checked не позволяет (по-видимому) изменять базовое значение и, следовательно, не вызывает обработчик onChange. Переход на defaultChecked, похоже, исправляет это:

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
Во-первых, почему бы не добавить onChange, который делает его this.setState({checked: !this.state.checked})проще, чем хранить значение. Затем тернарный оператор в проверяемом атрибуте:checked={this.state.checked ? 'checked': null}
— zackify

Так оно и началось, но, похоже, никогда не обновлялось. Так что я начал возиться с этим тут и там, чтобы отладить то, что не уволили. В идеале вернусь к простейшей форме после завершения :)
— jdarling

Предполагая, что ваш mountNode является фактическим dom-узлом, вам придется использовать this.refs.complete.getDOMNode().checked. см. скрипку jsfiddle.net/d10xyqu1
— trekforever

Он может просто использовать состояние вместо получения dom-узла: jsfiddle.net/d10xyqu1/1 Он работает нормально, должно быть, вы что-то опечатали.
— zackify

2
Игнорировать комментарий TL; DR - defaultChecked - это не всегда ответ
— Крис,

Ответы:


210

Чтобы получить отмеченное состояние вашего флажка, путь будет следующим:

this.refs.complete.state.checked

Альтернативный вариант - получить его из события, переданного в handleChangeметод:

event.target.checked

3
handleChange никогда не вызывается, не имеет значения, нажмете ли вы флажок или метку, handleChange не вызывается :(.
— jdarling

13
Попробуйте использовать defaultChecked = {this.state.complete} вместо "checked" во вводе.
— zbyte

Вот и все ... Искал вечно искал и ковырялся. Обновит вопрос с полным рабочим ответом, если другие тоже столкнутся с этим.
— jdarling

Но почему - с той же проблемой, но вы должны использовать checkedдля контролируемых компонентов: /
— Доминик

4
настройка checkedозначает, что состояние управляется вне компонента. Когда пользователь щелкает, вызывать нечего, так handleChangeкак состояние не обновляется. Вместо этого вам нужно будет прослушивать onClickи запускать обновление состояния там.
— zbyte 06

29

Ссылки в таких случаях лучше не использовать. Использование:

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

Есть несколько вариантов:

checked против defaultChecked

Первый будет реагировать как на изменения состояния, так и на щелчки. Последний будет игнорировать изменения состояния.

onClick против onChange

Первый всегда запускался по кликам. Последний не будет срабатывать при щелчках, если checkedатрибут присутствует в inputэлементе.


10

В сценарии, в котором вы НЕ хотите использовать обработчик onChange во входной DOM, вы можете использовать это onClickсвойство в качестве альтернативы. defaultChecked, Условие может оставить фиксированное состояние для 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>
        )
    }
 }

Надеюсь, это кому-то поможет в будущем.


10

Если у вас есть handleChangeфункция, которая выглядит так:

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

Вы можете создать настраиваемую onChangeфункцию, которая будет действовать как ввод текста:

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

не handleChangeна inputдолжно быть this.handleChange?
— Ardhi

5

Если кто-то ищет универсальный обработчик событий, можно более или менее использовать следующий код (при условии, что свойство name установлено для каждого ввода):

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

2

onChange не будет вызывать handleChange на мобильном устройстве при использовании defaultChecked. В качестве альтернативы вы можете использовать onClick и onTouchEnd.

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

1

В пользовательском интерфейсе материала состояние флажка можно получить как

this.refs.complete.state.switched
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.