React keypress事件仅采用初始状态的值,而不是更新后的值。
React keypress事件仅采用初始状态的值,而不是更新后的值。
我正在创建一个React应用程序,其中有一个名为input的状态,用于接收用户的输入。我希望当我按下回车键时,弹出框应该显示在状态中设置的输入。然而,当我点击enter键时,只显示在输入状态中设置的默认值。\n但是,当我点击一个按钮(我创建的用于在弹出框中显示输入的按钮)时,弹出框中显示的输入是正确的。\n请参考下面的代码片段:\n
import React, { useEffect, useRef, useState } from 'react'; export default function ShowAlertExample() { const [input, setInput ] = useState('1'); const handleInputChange = (e) => { setInput(e.target.value); } const handleShowAlert = () => { alert(input); } const checkKeyPress = (e) =>{ const { key, keyCode } = e; console.log(key, keyCode) if (keyCode === 13 ) { alert(input); } } useEffect(()=>{ window.addEventListener("keydown", checkKeyPress) return ()=>{ window.removeEventListener("keydown", checkKeyPress) } }, []) return (); }
\n我进行了一个更改,可以在下面的代码片段中看到。我从useEffect()
的依赖列表中删除了[]
,然后它开始正常工作,但是现在问题是每次我向输入框添加内容时,它都会添加和删除事件侦听器。我想这不是一个好的做法,如果我们正在创建一个大型应用程序的话。\n
import React, { useEffect, useRef, useState } from 'react'; export default function ShowAlertExample() { const [input, setInput ] = useState('1'); const handleInputChange = (e) => { setInput(e.target.value); } const handleShowAlert = () => { alert(input); } const checkKeyPress = (e) =>{ const { key, keyCode } = e; console.log(key, keyCode) if (keyCode === 13 ) { alert(input); } } useEffect(()=>{ window.addEventListener("keydown", checkKeyPress) console.log("event listener added") return ()=>{ console.log("event listener removed") window.removeEventListener("keydown", checkKeyPress) } }) return (); }
\n有没有办法可以添加具有所需功能的事件侦听器,而不会引起任何性能问题。也就是说,当我按下Enter键时,弹出框应该显示正确的输入。我参考了下面的Stack Overflow帖子并尝试使用useCallback()
,但它没有成功。\nhttps://stackoverflow.com/questions/55565444/how-to-register-event-with-useeffect-hooks#:~:text=hooks%20to%20below-,useEffect(()%20%3D%3E%20%7B%20window.,the%20effect%20once%2C%20imitating%20componentDidMount%20.
问题的原因是在"keydown"事件的checkKeyPress
回调中,将初始的input
状态值封装起来。每次调用回调时,都会访问到过时的状态封装。
解决方法是不要尝试使用全局的keyDown处理程序,而是直接将事件处理程序附加到要响应的元素上,这是React处理DOM交互的标准方式。这样可以解决过时状态封装的问题,使其成为标准的回调函数。
代码示例:
function ShowAlertExample() { const [input, setInput] = useState("1"); const handleInputChange = (e) => { setInput(e.target.value); }; const handleShowAlert = () => { alert(input); }; const checkKeyPress = (e) => { const { key, keyCode } = e; console.log(key, keyCode); if (keyCode === 13) { alert(input); } }; return (); }
为了更清晰起见,每次状态改变时,都会绑定一个新的checkKeyPress
并解绑上一个绑定的keydown
事件。只是现在React已经为我们处理了这一点,并且React已经使用事件委托来提高性能。
这种方法只在输入框获得焦点时起作用,如果用户点击输入框外部然后按下"Enter"键,则可能不起作用。然而,我同意你和Lakshya的观点,最好的解决方法是在这种情况下使用onSubmit()。实际上,我在这里没有使用
元素,而是在是的,这种方法只在输入框获得焦点时起作用,但这也是我询问你用例的原因。如果你需要一个全局的keypress处理程序,那么监听window/document是正确的方法,你只需要优化访问字段的值即可。
问题的出现原因是在旧的代码中,useEffect
中的空数组意味着在第一次渲染后添加了一个事件监听器到checkKeyPress
,现在checkKeyPress
关闭了input
的默认值。
解决方法是确保每次input
更新时,最新的checkKeyPress
(闭合最新input
)被添加为事件处理程序,并且删除旧的处理程序。
在旧的代码中,由于总是需要最新的input
状态值,所以必须将checkKeyPress
添加到useEffect
的依赖列表中,并且checkKeyPress
本身应该在useCallback
的依赖列表中有input
。
如果事件监听器涉及到React状态,那么每次状态更新都需要绑定和解绑事件处理程序,否则你将处理过时的状态。根据我的经验,在这种特定的用例中没有任何解决方法。另外,让我们考虑一个表单。你可能不希望在window上添加事件监听器,而是在表单元素上添加提交事件。React在后台也会在JSX重新渲染时绑定/解绑新的事件处理程序,以及表单。
此外,相比于显式地将事件绑定到window上,这种方法的性能更高,因为React在内部使用事件委托。
以上就是解决React keypress事件只使用初始状态值而不是更新后的值的原因和解决方法。