Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to add a keydown Event Listener for a react functional component

I’m trying to ‘move’ in my 10×10 grid by updating the activeCellId state. However none of the methods I tried works. This is my code.

const GridCells: React.FC = () => {
  const gridArray = [...Array(100).keys()];
  const color = [
    "bg-slate-50",
    "bg-slate-100",
    "bg-slate-200",
    "bg-slate-300",
    "bg-slate-400",
    "bg-slate-500",
    "bg-slate-600",
    "bg-slate-700",
    "bg-slate-800",
    "bg-slate-900",
  ];

  const [activeCellId, setActiveCellId] = useState(42);

  // useEffect(() => {
  //   document.addEventListener("keydown", updateActiveCellId, false);
  // }, []);  // this doesn't work. the activeCellId is only incremented once, and afterwards the setActiveCellId doesn't get called at all

  const updateActiveCellId = (e: React.KeyboardEvent) => {
    // will eventually be a switch case logic here, for handling arrow up, left, right down
    console.log(activeCellId);
    setActiveCellId(activeCellId + 1);
  };

  return (
    <div
      className="grid-rows-10 grid grid-cols-10 gap-0.5"
      // onKeyDown={updateActiveCellId}  this also doesn't work
    >
      {gridArray.map((value, id) => {
        const colorId = Math.floor(id / 10);
        return (
          <div
            key={id}
            className={
              "h-10 w-10 "
              + color[colorId] 
              + (id === activeCellId ? " scale-125 bg-yellow-400" : "")
            }
          >
            {id}
          </div>
        );
      })}
    </div>
  );
};

I’m trying to update a state in the react component by pressing certain keys. I’ve tried UseEffect with [] dep array and tried onKeyDown and it also doesn’t work. I also tried following this useRef way it doesn’t work too.

const innerRef = useRef(null);
  useEffect(() => {
    const div = innerRef.current;
    div.addEventListener("keydown", updateActiveCellId, false);
  }, []);  // this doesn't work at all

  const updateActiveCellId = (e: React.KeyboardEvent) => {
    console.log(activeCellId);
    setActiveCellId(activeCellId + 1);
  };

  return (
    <div
      className="grid-rows-10 grid grid-cols-10 gap-0.5"
      ref={innerRef}
    >
    ...
  )

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Try this:

useEffect(() => {
  document.addEventListener("keydown", updateActiveCellId, false);
  
  return () => {
    document.removeEventListener("keydown", updateActiveCellId, false);
  }
}, [activeCellId]);

The [activeCellId] is the dependency of useEffect. Everytimes activeCellId changes, the function inside useEffect will run.

You had an empty dependency, so it ran on initial component mount only.

The returned function containing removeEventListner is executed when the component unmounts (See cleanup function in the docs). That is to ensure you have only one event listener runnign at once.

Documentation

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading