React: 点击处理程序中的event.preventDefault不会阻止调用onChange

创建于 2017-02-17  ·  6评论  ·  资料来源: facebook/react

您是否要请求功能或报告错误

臭虫!

目前的行为是什么?

使用onClickonChange处理程序呈现类型checkboxinput元素时,即使event.preventDefault()仍会调用onChange event.preventDefault()onClick处理程序中调用。

如果当前行为是错误,请通过https://jsfiddle.net或类似文件(模板:https://jsfiddle.net/reactjs/69z2wepo/)提供重现步骤,并尽可能提供问题的最小演示。

http://jsfiddle.net/rf3w7apc/

预期的行为是什么?

onClick处理程序中调用event.preventDefault应该可以防止发生默认操作(或撤消其效果),该操作将更新input元素的值。 这应该阻止任何change事件侦听器被调用。 请参阅https://jsfiddle.net/L1eskzsq/了解预期行为

哪个版本的React,以及哪个浏览器/操作系统受此问题影响?

使用来自主版本macOS 10.12.2的构建进行了测试,并在以下方面进行了验证:

  • Chrome 56.0.2924.87(64位)
  • Firefox 51.0.1(64位)

两种情况下,Safari 10.0.2都会调用change事件监听器。

DOM Bug

最有用的评论

有关系吗在复选框onChange preventDefault调用https :

所有6条评论

change正在被创建的事件ChangeEventPlugin为响应topChange ,在你的onClick处理甚至被称为(所以之前preventDefault电话),在这里: https

该插件试图确定复选框的值是否会更改,如果是,它将在change事件中排队。 它使用inputValueTracking功能将上一个值与下一个值进行比较,以做出此决定,在这里: https :

nextValue像这样直接从DOM中获取: value = isCheckable(node) ? '' + node.checked : node.value; https://github.com/facebook/react/blob/master/src/renderers/dom/shared/inputValueTracking.js# L56

问题在于,此时的node.checked值暂时为true,因此在首次单击后为:

lastValue == false (正确)
nextValue == true (不正确)

并再次单击复选框,将不再触发change事件,因为这些值是:

lastValue == true (不正确)
nextValue == true (不正确)

总体而言,问题似乎是React可以在调用onClick的preventDefault之前询问DOM节点的checked值是什么。

感谢@karelskopek@Mintaffee在此方面的帮助。

@aweary您认为这值得解决吗?

这个没有进展吗? 我正在使用React v16.2,并且行为相同-首次触发onChange,而随后的点击不会触发它。 我会在这里说非常优先的问题。

有关系吗在复选框onChange preventDefault调用https :

在React 16.8.6中仍然是一个问题。 一种可能的解决方法是在onClick处理程序中执行所有操作:

const radios = ['one', 'two', 'three'];

class Row extends Component {
  constructor(props) {
    super(props);
    this.onClick = this.onClick.bind(this);
    this.onChange = this.onChange.bind(this);
  }

  render() {
    const { value } = this.props;
    return (
      <div className="row">
        <div className="radio-group">
          {radios.map(radio => (
            <label key={radio} className="radio">
              <input
                type="radio"
                name="radio"
                value={radio}
                checked={radio === value}
                onClick={this.onClick}
                onChange={this.onChange}
              /><span>Radio</span>
            </label>
          ))}
        </div>
      </div>
    );
  }

  onClick(event) {
    // Check something to prevent radio change
    if (...) {
      event.preventDefault();
      return;
    }
    // Sync value in the store
    this.props.setValue(event.target.value);
  }
  onChange() {
    // We need this empty handler to suppress React warning:
    // "You provided a `checked` prop to a form field without an `onChange` handler.
    // This will render a read-only field. If the field should be mutable use `defaultChecked`.
    // Otherwise, set either `onChange` or `readOnly`"
  }
}

如果您使用受控组件,我发现的另一个选择是简单地将value保持不变:

onChange(event) {
  // Check something to prevent radio change
  if (...) {
    return;
  }
  // Sync value in the store
  this.props.setDateTime(event.target.value);
}

对于更简单的解决方案,您可以在onMouseDown事件上执行e.preventDefault以防止触发onChange。

onMouseDown(e) { if (...) { e.preventDefault(); return; } }

此页面是否有帮助?
0 / 5 - 0 等级