Reputation: 521
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!
Upvotes: 2
Views: 1102
Reputation: 126
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>
);
}
Upvotes: 1