Apakah Anda ingin meminta fitur atau melaporkan bug ?
Bug!
Bagaimana perilaku saat ini?
Saat merender elemen input
tipe checkbox
dengan handler onClick
dan onChange
, onChange
masih dipanggil meskipun event.preventDefault()
dipanggil dalam penangan onClick
.
Jika perilaku saat ini adalah bug, berikan langkah-langkah untuk mereproduksi dan jika mungkin demo minimal dari masalah tersebut melalui https://jsfiddle.net atau yang serupa (template: https://jsfiddle.net/reactjs/69z2wepo/).
Apa perilaku yang diharapkan?
Memanggil event.preventDefault
dalam penangan onClick
seharusnya mencegah tindakan default terjadi (atau membatalkan efeknya), yaitu memperbarui nilai elemen input
. Ini akan menghentikan pemroses acara change
dari pemanggilan. Lihat https://jsfiddle.net/L1eskzsq/ untuk perilaku yang diharapkan
Versi React mana, dan browser / OS mana yang terpengaruh oleh masalah ini?
Diuji menggunakan build dari master, macOS 10.12.2, diverifikasi di:
Safari 10.0.2 memanggil pendengar acara change
dalam kedua kasus tersebut.
Acara change
sedang dibuat oleh ChangeEventPlugin
sebagai tanggapan atas topChange
, bahkan sebelum penangan onClick
dipanggil (jadi sebelum preventDefault
call), di sini: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js#L338
Plugin ini mencoba mencari tahu apakah nilai kotak centang akan berubah, dan jika ya itu akan mengantri acara change
. Ini menggunakan fungsionalitas inputValueTracking
untuk membandingkan nilai sebelumnya dengan nilai berikutnya untuk membuat keputusan ini, di sini: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/ inputValueTracking.js # L154
nextValue
diambil langsung dari DOM seperti ini: value = isCheckable(node) ? '' + node.checked : node.value;
https://github.com/facebook/react/blob/master/src/renderers/dom/shared/inputValueTracking.js# L56
Masalahnya adalah bahwa nilai node.checked
sementara benar pada saat ini, jadi setelah klik pertama adalah:
lastValue == false
(benar)
nextValue == true
(salah)
dan pada klik berikutnya pada kotak centang, peristiwa change
tidak lagi diaktifkan, karena nilainya adalah:
lastValue == true
(salah)
nextValue == true
(salah)
Secara keseluruhan masalahnya tampaknya React menanyakan DOM berapa nilai checked
dari node itu, sebelum preventDefault di onClick
dapat dipanggil.
Terima kasih @karelskopek dan @Mintaffee atas bantuan Anda untuk menggali lebih dalam.
@aweary Menurut Anda apakah ini layak untuk
Tidak ada kemajuan dengan yang ini? Saya menggunakan React v16.2 dan perilakunya sama - onChange dipicu pertama kali dan klik berikutnya tidak memicunya. Saya akan mengatakan masalah prioritas cukup tinggi di sini ..
Apakah ini terkait? preventDefault
dipanggil di kotak centang onChange
menyebabkan React dan status browser tidak sinkron: https://codesandbox.io/s/0qpr936xkv
Masih masalah di React 16.8.6. Salah satu solusi yang mungkin adalah melakukan semuanya di onClick
handler:
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`"
}
}
Jika Anda menggunakan komponen terkontrol, opsi lain yang saya temukan adalah membiarkan nilai dalam status tidak berubah:
onChange(event) {
// Check something to prevent radio change
if (...) {
return;
}
// Sync value in the store
this.props.setDateTime(event.target.value);
}
Untuk solusi yang lebih sederhana, Anda dapat melakukan e.preventDefault pada peristiwa onMouseDown untuk mencegah pengaktifan onChange.
onMouseDown(e) {
if (...) {
e.preventDefault();
return;
}
}
Komentar yang paling membantu
Apakah ini terkait?
preventDefault
dipanggil di kotak centangonChange
menyebabkan React dan status browser tidak sinkron: https://codesandbox.io/s/0qpr936xkv