React keypress event taking only initial state values and not updated values

I am creating a React application in which I have one state called input which is taking input from user . I want that when I press enter key , alert should display the input which is getting set in state . However, on clicking enter key , only default value set in input state is getting displayed .

But when I click on a button (which I have created to display the input in alert), then the input displayed in alert is correct .

Please see the code snippet below for reference .

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 (
    <div>
      <header className="App-header">
        <input value={input} onChange={handleInputChange} />
       <button onClick={handleShowAlert}>Show Alert</button>
      </header>
    </div>
  );
}

I made one change which can be seen in the code snippet below . I removed the [] from dependency list of useEffect() and it started working fine . But now the issue is it is adding and removing event listener each time I add something to input . This is not a good practice I guess if we are creating a big application .

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 (
    <div>
      <header className="App-header">
        <input value={input} onChange={handleInputChange} />
       <button onClick={handleShowAlert}>Show Alert</button>
      </header>
    </div>
  );
}

Is there anyway I can add event listener with the desired functionality without causing any performance issue . That is when I press ‘Enter’ key , the alert should display the correct input . I have referred to the below stackoverflow post and tried using useCallback() but it didn’t work out .

https://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.

2 thoughts on “React keypress event taking only initial state values and not updated values”

  1. Issue

    You’ve enclosed the initial input state value in the checkKeyPress callback for the "keydown" event.

    Solution

    Instead of alerting with the enclosed value have checkKeyPress call the same alert handler the button onClick uses.

    const checkKeyPress = (e) =>{
      const { key, keyCode } = e;
      console.log(key, keyCode)
      if (keyCode === 13 ) {
        handleShowAlert();
      }
    }
    

    Edit react-keypress-event-taking-only-initial-state-values-and-not-updated-values

    Reply
  2. Since you always require the latest state value of input, you will have to add it to your useEffect‘s dependency list.

      useEffect(()=>{
        window.addEventListener("keydown", checkKeyPress)
        return ()=>{
          window.removeEventListener("keydown", checkKeyPress)
        }
      }, [input])
    
    Reply

Leave a Comment