如何定义使用状态的按键处理程序?

问题描述 投票:0回答:1

我使用函数组件是因为我知道这是现代的方式。我想定义一个访问组件状态的键处理程序。直观优雅的方法行不通。

import React, { useState, useEffect } from "react"

我尝试了3种方法:

方法1

export default function CounterApp() {
  const [counter, setCounter] = useState(0);

  useEffect(() => document.addEventListener(
    'keydown', 
    (e) => {
      console.log("Got keystroke", e.key, counter);
      if (e.key === "1") {
        setCounter(counter + 1);
      }
    }
  ), []);

  console.log("render");
  return  <div>The counter is: {counter}</div>
}

方法二:

export default function CounterApp() {
  const [counter, setCounter] = useState(0);

  useEffect(
    () => document.addEventListener('keydown', keyhandler),
    []
  );

  function keyhandler(e) {
    console.log("Got keystroke", e.key, counter);
    if (e.key === "1") {
      setCounter(counter + 1);
    }
  }

  console.log("render");
  return  <div>The counter is: {counter}</div>
}

方法三:

export default function CounterApp() {
  const [counter, setCounter] = useState(0);

  useEffect(() => {
    document.addEventListener('keydown', keyhandler);
    return () => document.removeEventListener('keydown', keyhandler);
  }, [counter]);

  function keyhandler(e) {
    console.log("Got keystroke", e.key, counter);
    if (e.key === "1") {
      setCounter(counter + 1);
    }
  }

  console.log("render");
  return  <div>The counter is: {counter}</div>
}

方法3确实有效,但似乎需要大量打字,可能效率低下(频繁调用

useEffect
),而且容易出错,所以我想知道为什么更直接的方法不起作用。我更愿意在组件的生命周期中仅添加一次事件侦听器,添加一个永远不会更改的函数(因此无需将其添加为
useEffect
依赖项),尽管该函数引用了一个确实会更改的状态变量。 React 是否真的需要在状态变量输入发生变化时重新解析函数定义?第三种方法是否正确且最佳?前两种方法有什么问题吗?

reactjs react-hooks
1个回答
0
投票

方法3很接近(它可以工作,但并不理想,就像你说的那样),但是你不应该在效果之外定义

keyhandler
,你应该在效果内部定义它。

您的主要问题(在方法 2 中也是如此,该方法几乎有效,但仍然不理想,因为

useEffect
中缺少返回函数)是您缺少状态更新器作为函数,而是捕获了
counter
当您的事件侦听器被附加时(第一次渲染时它始终为 0,并且每次按下某个键时
counter
仍将是 0)。

这个:

setCounter(c => c+1)

而不是:

setCounter(counter+1)

如果使用函数更新状态,则只需在安装时应用效果,而不是在计数器更改时应用效果:

export default function CounterApp() {
    const [counter,setCounter] = useState(0);

    useEffect(() => {
        const keyhandler = (e) => {
          if(e.key === "1") setCounter(c => c+1)
        }
    
        document.addEventListener('keydown', keyhandler);
        return () => document.removeEventListener('keydown', keyhandler);
    },[]);

    console.log("render");
    return  <div>The counter is: {counter} </div>
}
© www.soinside.com 2019 - 2024. All rights reserved.