Hai, Saya menggunakan mode Kontrol masukan dan berlangganan acara onKeyDown
dan onChange
. Ini akan memicu efek saat pengguna memasuki ruang angkasa. Namun, ruang tersebut tidak ditampilkan di layar. Apakah ini bug di React atau ada yang salah dengan cara saya menggunakannya. Tapi berlangganan onKeyUp
itu normal. Ini membingungkan.
Versi React: 16.13.1 dan lama
Tautan ke contoh kode:
import React, { useState,useEffect } from 'react'
const App = () => {
const [count, setCount] = useState(0)
const [value, setValue] = useState('')
const [code, setCode] = useState('add')
useEffect(() => {
if (code === 'add') {
setCount(c => c + 1)
} else {
setCount(c => c - 1)
}
}, [code, setCount])
const keyDown = e => {
if (e.keyCode === 32) {
console.log('space~')
if (code === 'add') {
setCode('minus')
} else {
setCode('add')
}
}
}
const handleChange = e => {
setValue(e.target.value)
}
return (
<div>
<div>{count}</div>
<br />
<input onKeyDown={keyDown} value={value} onChange={handleChange} />
</div>
)
}
export default App
elemen masukan tidak dapat menerima ruang
elemen masukan dapat menerima ruang
Sepertinya pembaruan status dalam penangan onKeyDown
menyela kejadian dan mencegah penangan onChange
dipanggil. Karena komponen terkontrol hanya menampilkan apa yang Anda perintahkan (status value
dalam contoh Anda) ini mengakibatkan karakter spasi tidak pernah muncul.
Ini tampak seperti bug bagi saya dalam cara kedua peristiwa ini saling mempengaruhi.
cc @trueadm @gaearon atas keahlian sistem acara mereka
Hai, saya baru di sini, mencoba mempelajari arsitektur React.
@bvaughn Berikut adalah sesuatu yang saya temukan tentang masalah tersebut.
onKeyDown
acara tidak memblokir onChange
melainkan dipicu sebelum input diubah. Pada dasarnya, onKeyDown
lebih awal dari onChange
karena input teks terjadi di onKeyUp
.
Dalam kasus khusus ini, masalahnya adalah bahwa dalam keyDown
, ketika setCode
memanggil, pada dispatchAction
_Fiber_ memiliki memoizedState
tanpa karakter baru (jelas) dan e
yang akan ditambahkan. Pada akhirnya, ini menambahkan karakter baru ke input. Kemudian useEffect()
memicu dispatchAction
lagi dalam _same queue_ (tidak yakin apakah itu antrian) tetapi tidak tahu apa-apa tentang alat peraga yang diperbarui. Akibatnya, ketika commitRoot
, itu mengembalikan pendingProps
yang sama seperti di memoizedState
. Singkatnya, karakter (spasi dalam contoh ini) ditambahkan dan kemudian status lama segera pulih tanpa karakter baru (spasi), jadi sepertinya tidak menambahkan apa pun.
Sebagai contoh tidak menggunakan _same queue_ (?), Contoh khusus ini:
useEffect(() => {
if (code === 'add') {
setCount(c => c + 1)
} else {
setCount(c => c - 1)
}
}, [code, setCount])
dapat dimodifikasi menjadi:
useEffect(() => {
if (code === 'add') {
setTimeout(() => setCount(c => c + 1), 0)
} else {
setTimeout(() => setCount(c => c - 1), 0)
}
}, [code, setCount])
dan itu akan berhasil.
Saya harap itu masuk akal.
Mengalami masalah yang sama ini, membungkus panggilan setState saya dalam setTimeout di penangan keydown memperbaikinya.
Saya penasaran untuk mengetahui apakah ini adalah sesuatu yang seharusnya bekerja secara berbeda di bawah tenda di React atau jika kesalahan ini menunjukkan kesalahan yang lebih besar atau pola buruk di sisi pengembang?