簡體   English   中英

狀態是<empty string>在按鍵事件上調用函數時

[英]State is <empty string> when function is called on key event

在 React 中,我有許多按鈕(想象一個帶有數字的 PIN 布局)在點擊時更新狀態。 我還在document中添加了一個事件偵聽器,因此鍵盤上的按鍵也會更新 pin。 但是,有一個奇怪的問題。 當我通過單擊按鈕添加數字時,狀態正常工作並且一切正常,但是當我按下物理鍵盤上的鍵時,狀態會更新,但會記錄為<empty string>

這是代碼:

export default function Keypad() {
    const [pin, setPin] = useState("");

    function addNumber(num) {
        console.log(pin); // returns the correct pin with handleKeyClick, returns <empty string> with handleKeyDown
        if (pin.length < 6) { // only works if the pin is not <empty string>
            setPin((pin) => [...pin, num.toString()]); // works correctly with both handleKeyClick and handleKeyDown even if pin logged <empty string>!
        }
    }

    function handleKeyClick(num) {
        addNumber(num);
    }

    function handleKeyDown(e) {
        if (!isNaN(e.key)) {
            addNumber(e.key);
        }
    }

    useEffect(() => {
        document.addEventListener("keydown", handleKeyDown);

        return () => {
            document.removeEventListener("keydown", handleKeyDown);
        };
    }, []);

    return (
        <div>
            {/* just one button for example */}
            <button onClick={() => handleKeyClick(9)}>9</button>
        </div>
    )
}

我猜這是因為document無法訪問pin狀態,但如果是這種情況, setPin應該工作。 我對嗎?

您的組件在偵聽 DOM 事件時不保留引用,這個答案有一些簡潔的代碼,用於使用相當簡單的鈎子偵聽窗口事件。 當應用於您的代碼時,它按預期工作:

 const {useState, useEffect, useRef} = React; // Hook function useEventListener(eventName, handler, element = window){ // Create a ref that stores handler const savedHandler = useRef(); // Update ref.current value if handler changes. // This allows our effect below to always get latest handler ... // ... without us needing to pass it in effect deps array ... // ... and potentially cause effect to re-run every render. useEffect(() => { savedHandler.current = handler; }, [handler]); useEffect( () => { // Make sure element supports addEventListener // On const isSupported = element && element.addEventListener; if (!isSupported) return; // Create event listener that calls handler function stored in ref const eventListener = event => savedHandler.current(event); // Add event listener element.addEventListener(eventName, eventListener); // Remove event listener on cleanup return () => { element.removeEventListener(eventName, eventListener); }; }, [eventName, element] // Re-run if eventName or element changes ); }; const Keypad = (props) => { const [pin, setPin] = useState([]); function addNumber(num) { console.log(pin); // returns the correct pin with handleKeyClick, returns <empty string> with handleKeyDown if (pin.length < 6) { // only works if the pin is not <empty string> setPin((pin) => [...pin, num.toString()]); // works correctly with both handleKeyClick and handleKeyDown even if pin logged <empty string>! } } function handleKeyClick(num) { addNumber(num); } function handleKeyDown(e) { if (!isNaN(e.key)) { addNumber(e.key); } } useEventListener("keydown", handleKeyDown) return ( <div> {/* just one button for example */} <button onClick={() => handleKeyClick(9)}>9</button> </div> ) return "Hello World" } ReactDOM.render(<Keypad />, document.getElementById("root"))
 <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM