Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

111
Visualizações
State is <empty string> when function is called on key event

In React, I have a number of buttons (imagine a PIN layout with numbers) that update the state on click. I also added an event listener to the document so pressing keys on the keyboard updates the pin too. However, there's a strange problem. When I add a number by clicking a button, the state is working correctly and everything is fine, but when I press a key on a physical keyboard, the state updates, but logs as <empty string>!

Here is the code:

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>
    )
}

I guess this is because document can't access the pin state, but if it was the case, the setPin shouldn't work either. Am I right?

about 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

Your component does not keep a reference when listening to DOM events, this answer has some neat code for listening to window events using a fairly simple hook. When applied to your code, it works as expected:

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>

about 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda