React: 错误:onKeyDown中无关的状态更新会阻止onChange并破坏受控组件

创建于 2020-07-09  ·  3评论  ·  资料来源: facebook/react

嗨,我使用输入控制模式并订阅onKeyDownonChange事件。 用户进入太空时会触发效果。 但是,该空间不会显示在屏幕上。 这是React的错误还是我使用它的方式有问题? 但是订阅onKeyUp是正常的。 这很困惑。

React版本:16.13.1和旧的

重现步骤

  1. 进入太空
  2. 输入元素在屏幕上不显示空间

链接到代码示例:

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

当前行为

输入元素无法接收空格

预期的行为

输入元素可以接收空间

DOM Unconfirmed Bug

所有3条评论

看起来onKeyDown处理程序中的状态更新会中断该事件并阻止onChange处理程序被调用。 由于受控组件仅显示您告诉他们的内容(示例中的value状态),因此导致空格字符永远不会出现。

这两个事件相互影响的方式对我来说似乎是个错误。

cc @trueadm @gaearon的活动系统专业知识

嗨,我是新来的,试图学习React架构。

@bvaughn这是我发现的有关此问题的信息。

onKeyDown事件不会阻止onChange而是它会在修改输入之前触发。 基本上, onKeyDownonChange早,因为文本输入发生在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的幕后工作上有所不同,或者该错误是否指向开发人员方面的更大错误或错误模式?

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