React keypress事件仅采用初始状态的值,而不是更新后的值。

15 浏览
0 Comments

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.

0
0 Comments

问题的原因是在"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是正确的方法,你只需要优化访问字段的值即可。

0
0 Comments

问题的出现原因是在旧的代码中,useEffect中的空数组意味着在第一次渲染后添加了一个事件监听器到checkKeyPress,现在checkKeyPress关闭了input的默认值。

解决方法是确保每次input更新时,最新的checkKeyPress(闭合最新input)被添加为事件处理程序,并且删除旧的处理程序。

在旧的代码中,由于总是需要最新的input状态值,所以必须将checkKeyPress添加到useEffect的依赖列表中,并且checkKeyPress本身应该在useCallback的依赖列表中有input

如果事件监听器涉及到React状态,那么每次状态更新都需要绑定和解绑事件处理程序,否则你将处理过时的状态。根据我的经验,在这种特定的用例中没有任何解决方法。另外,让我们考虑一个表单。你可能不希望在window上添加事件监听器,而是在表单元素上添加提交事件。React在后台也会在JSX重新渲染时绑定/解绑新的事件处理程序,以及表单。

此外,相比于显式地将事件绑定到window上,这种方法的性能更高,因为React在内部使用事件委托。

以上就是解决React keypress事件只使用初始状态值而不是更新后的值的原因和解决方法。

0