Флажок 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.