Флажок 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>
    );
  }
});
jdarling
источник
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
zbyte
источник
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элементе.

Lin
источник
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>
        )
    }
 }

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

akiespenc
источник
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,
      },
    });
  }}
/>
spencer.sm
источник
не 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
Сакши Нагпал
источник