定义使用状态的密钥处理程序的最佳实践是什么?

问题描述 投票: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.