機能をリクエストしバグを報告しますか?
バグ!
現在の動作は何ですか?
onClick
およびonChange
ハンドラーを使用してタイプcheckbox
input
要素をレンダリングすると、 event.preventDefault()
あっても、 onChange
が呼び出されます。 event.preventDefault()
はonClick
ハンドラーで呼び出されます。
現在の動作がバグである場合は、 https://jsfiddle.netまたは同様の方法(テンプレート:https://jsfiddle.net/reactjs/69z2wepo/)を介して、再現する手順と、可能であれば問題の最小限のデモを提供してください。
期待される動作は何ですか?
onClick
ハンドラーでevent.preventDefault
を呼び出すと、デフォルトのアクションが発生しないようにする(またはその効果を元に戻す)必要があります。これは、 input
要素の値を更新することです。 これにより、 change
イベントリスナーが呼び出されなくなります。 予想される動作については、 https://jsfiddle.net/L1eskzsq/を参照して
この問題の影響を受けるReactのバージョンとブラウザ/ OSはどれですか?
マスターからのビルド、macOS 10.12.2を使用してテストし、以下で検証しました。
Safari 10.0.2は、どちらの場合もchange
イベントリスナーを呼び出します。
change
イベントは、 onClick
ハンドラーが呼び出される前に(つまり、 preventDefault
前に)、 topChange
への応答としてChangeEventPlugin
によって作成されます。 preventDefault
call)、ここ: 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
値が一時的に真であるため、最初のクリック後は次のようになることです。
lastValue == false
(正解)
nextValue == true
(不正解)
チェックボックスを次にクリックすると、値が次のようになるため、 change
イベントは発生しなくなります。
lastValue == true
(不正解)
nextValue == true
(不正解)
全体的な問題は、 onClick
のpreventDefaultを呼び出す前に、Reactがノードのchecked
値をDOMに要求していることのようです。
これを掘り下げるのを手伝ってくれた@karelskopekと@Mintaffeeに感謝します。
@awearyこれは解決する価値があると思いますか?
これで進歩はありませんか? React v16.2を使用していますが、動作は同じです。onChangeは最初にトリガーされ、その後のクリックではトリガーされません。 ここではかなり優先度の高い問題だと思います。
これは関係がありますか? チェックボックスonChange
preventDefault
呼び出されると、Reactとブラウザーの状態が同期しなくなります: //codesandbox.io/s/0qpr936xkv
React16.8.6ではまだ問題です。 考えられる回避策の1つは、 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`"
}
}
制御されたコンポーネントを使用
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;
}
}
最も参考になるコメント
これは関係がありますか? チェックボックス
onChange
preventDefault
呼び出されると、Reactとブラウザーの状態が同期しなくなります: //codesandbox.io/s/0qpr936xkv