Home > Back-end >  Increase and decrease the number using addEventListener keydown in React
Increase and decrease the number using addEventListener keydown in React

Time:02-22

I wrote a program that adds or subtracts a unit to count by pressing the up and down keys on the keyboard. The problem is that the program does not work properly. When you press the key, look at the console, which runs several times, while each time you press the key, it only has to run once. This is a problem that crashes after pressing the up or down buttons a few times, please help

import React, { useState } from "react";

export default function Example() {
  const [count, setCount] = useState(0);

  document.addEventListener("keydown", function (e) {
    switch (e.keyCode) {
      case 38:
        setCount(count   1);
        console.log(count);
        break;
      case 40:
        setCount(count - 1);
        console.log(count);
        break;
    }
  });
  return (
    <div>
      <p>You clicked {count} times</p>
    </div>
  );
}

CodePudding user response:

You are adding an event handler every time the component is rendered. The component is re-rendered whenever the state changes. It's an exponential loop, hence your application "crashes".

  • Use useEffect to attach the event listener once the component is mounted and remove it again once the component is unmounted.
  • Provide a callback to setCount to access the current count.
export default function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const keyDownCallback = function (e) {
      switch (e.keyCode) {
        case 38:
          setCount((count) => count   1);
          break;
        case 40:
          setCount((count) => count - 1);
          break;
      }
    };

    document.addEventListener("keydown", keyDownCallback);

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

  return (
    <div>
      <p>You clicked {count} times</p>
    </div>
  );
}

See demo

Documentation

CodePudding user response:

Well each time your component re-renders, it attaches that event listener again and again and calls setCount too many times and re-renders component too many times. Therefore your program falls into infinite loop. I think you should try useEffect and useLayoutEffect hooks.

Edit

import React from "react";

export default function App() {
  const [count, setCount] = React.useState(0);

  const handleUpdateCount = React.useCallback(
    (value) => setCount((prevCount) => prevCount   value),
    [setCount]
  );

  React.useEffect(() => {
    const keyDownCallback = (e) => {
      switch (e.keyCode) {
        case 38:
          handleUpdateCount(1);
          break;
        case 40:
          handleUpdateCount(-1);
          break;
        default:
          console.log("default");
      }
    };

    document.addEventListener("keydown", keyDownCallback);

    return () => document.removeEventListener("keydown", keyDownCallback);
  }, [handleUpdateCount]);

  return (
    <div>
      <p>You clicked {count} times</p>
    </div>
  );
}

In these way, we prevent from extra re-renders.

And about useLayoutEffect, this hook runs given callback after all DOM mutations, But according to official React documentation, We should tend to use useEffect as possible. https://reactjs.org/docs/hooks-reference.html

CodePudding user response:

You have to put document.addEventListener in an useEffect or it will add an event listener each time component re-render

useEffect(() => {
   document.addEventListener("keydown", function (e) {
    switch (e.keyCode) {
      case 38:
        setCount(count   1);
        console.log(count);
        break;
      case 40:
        setCount(count - 1);
        console.log(count);
        break;
    }
  });
}, [])
  • Related