嗨,我使用输入控制模式并订阅onKeyDown
和onChange
事件。 用户进入太空时会触发效果。 但是,该空间不会显示在屏幕上。 这是React的错误还是我使用它的方式有问题? 但是订阅onKeyUp
是正常的。 这很困惑。
React版本:16.13.1和旧的
链接到代码示例:
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
输入元素无法接收空格
输入元素可以接收空间
看起来onKeyDown
处理程序中的状态更新会中断该事件并阻止onChange
处理程序被调用。 由于受控组件仅显示您告诉他们的内容(示例中的value
状态),因此导致空格字符永远不会出现。
这两个事件相互影响的方式对我来说似乎是个错误。
cc @trueadm @gaearon的活动系统专业知识
嗨,我是新来的,试图学习React架构。
@bvaughn这是我发现的有关此问题的信息。
onKeyDown
事件不会阻止onChange
而是它会在修改输入之前触发。 基本上, onKeyDown
比onChange
早,因为文本输入发生在onKeyUp
。
在这种情况下,问题是在keyDown
,当setCode
调用时,第一个dispatchAction
_Fiber_具有memoizedState
而没有新字符(显然)和e
这将被添加。 最后,它将新字符添加到输入中。 然后useEffect()
在_same queue_(不确定它是否在队列)内再次触发dispatchAction
,但它对更新的道具一无所知。 其结果是,当它commitRoot
,它恢复pendingProps
这是因为它们是在相同的memoizedState
。 简而言之,先添加字符(在此示例中为空格),然后立即恢复旧状态而没有新字符(空格),因此看起来它没有添加任何内容。
作为不使用_same queue_(?)的示例,此特定示例:
useEffect(() => {
if (code === 'add') {
setCount(c => c + 1)
} else {
setCount(c => c - 1)
}
}, [code, setCount])
可以修改为:
useEffect(() => {
if (code === 'add') {
setTimeout(() => setCount(c => c + 1), 0)
} else {
setTimeout(() => setCount(c => c - 1), 0)
}
}, [code, setCount])
它会工作。
我希望这是有道理的。
遇到同样的问题,将我的setState调用包装在keydown处理程序中的setTimeout中,以解决此问题。
我很想知道这是否应该在React的幕后工作上有所不同,或者该错误是否指向开发人员方面的更大错误或错误模式?