简体   繁体   中英

How to catch keydown event inside child component

There is a component that catches keyDown event. It has a counter which is incremented by Arrow Right and decremented by Arrow Left.

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

  // eslint-disable-next-line consistent-return
  React.useEffect(() => {
    const keyboardHandler = (event) => {
      const key = parseInt(event.keyCode || event.which || 0, 10);
      switch (key) {
        case LEFT_ARROW:
          setPosition((p) => p - 1);
          break;
        case RIGHT_ARROW:
          setPosition((p) => p + 1);
          break;
        default:
          break;
      }
    };

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

  return (
    <div className="App">
      {position}
      <br />
      <Inner />
    </div>
  );
}

It works fine.

Now, there is a child component that has an input field. I would like it to catch arrow left and arrow right so it IS NOT propagated to the main component. My guess was:

export default function Inner() {
  React.useEffect(() => {
    const keyboardHandler = (event) => {
      const key = parseInt(event.keyCode || event.which || 0, 10);
      switch (key) {
        case LEFT_ARROW:
          event.stopPropagation();
          break;
        case RIGHT_ARROW:
          event.stopPropagation();
          break;
        default:
          break;
      }
    };

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

  return <input name="test" />;
}

But it does not seem to work. The child receives the event AND the parent receives the event as well. I guess the problem is that the event handler is linked to the window.document, but how do I change it?

Here is the codesandbox example: https://codesandbox.io/s/bold-pare-fvd305

Thank you in advance!

You can ignore the keyDown if it was made inside the input field. You just need to check event.target :

import "./styles.css";
import React from "react";


const LEFT_ARROW = 37;
const RIGHT_ARROW = 39;

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

  // eslint-disable-next-line consistent-return
  React.useEffect(() => {
    const keyboardHandler = (event) => {
      const key = parseInt(event.keyCode || event.which || 0, 10);
      if (event.target.name !== "test"){
        switch (key) {
          case LEFT_ARROW:
            setPosition((p) => p - 1);
            break;
          case RIGHT_ARROW:
            setPosition((p) => p + 1);
            break;
          default:
            break;
        }
      };
    }
    window.document.addEventListener("keydown", keyboardHandler);
    return () => {
      window.document.removeEventListener("keydown", keyboardHandler);
    };
  }, []);

  return (
    <div className="App">
      {position}
      <br />
      <input name="test" />
    </div>
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM