Last active
April 27, 2022 20:33
-
-
Save whoisryosuke/04a296edd771d8cc2d2da172ba98d775 to your computer and use it in GitHub Desktop.
React - useKeyPress hook modified with pressed / down / up callbacks - see example: https://codesandbox.io/s/r3f-gamepad-and-keyboard-input-in-component-usekeypress-method-clsbsv?file=/src/hooks/useKeyPress.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { useEffect, useState } from "react" | |
| // Modified the useKeyPress from useHooks: https://usehooks.com/useKeyPress/ | |
| // Takes a `pressMethod` that will run continuously "every frame" (1/60 second - not locked tho) | |
| // And also accepts a `downMethod` and `upMethod` for a single call | |
| // And still returns a simple true/false for the keypress for convenience/use in React | |
| // Ideally all the methods should be an properties of 1 object so user doesn't have to set noop functions to get deeper params | |
| export default function useKeyPress(targetKey: string, pressMethod?: () => void, downMethod?: () => void, upMethod?: () => void): boolean { | |
| // State for keeping track of whether key is pressed | |
| const [keyPressed, setKeyPressed] = useState(false) | |
| // If pressed key is our target key then set to true | |
| function downHandler({ key }): void { | |
| if (key === targetKey) { | |
| setKeyPressed(true) | |
| downMethod?.() | |
| } | |
| } | |
| // If released key is our target key then set to false | |
| const upHandler = ({ key }): void => { | |
| if (key === targetKey) { | |
| setKeyPressed(false) | |
| upMethod?.() | |
| } | |
| } | |
| // This is the "continuous" press magic | |
| // When the user presses key, | |
| // we set the `pressMethod` to run constantly using setInterval | |
| useEffect(() => { | |
| let interval | |
| if (keyPressed && pressMethod) { | |
| // We loop the function to simulate it happening every frame | |
| interval = setInterval(pressMethod, 1000 / 60) | |
| } | |
| // This clears interval when component dismounts so it won't keep running | |
| return () => { | |
| if (interval) clearInterval(interval) | |
| } | |
| }, [keyPressed, pressMethod]) | |
| // Add event listeners for keypress | |
| useEffect(() => { | |
| window.addEventListener("keydown", downHandler) | |
| window.addEventListener("keyup", upHandler) | |
| // Remove event listeners on cleanup | |
| return () => { | |
| window.removeEventListener("keydown", downHandler) | |
| window.removeEventListener("keyup", upHandler) | |
| } | |
| }, []) // Empty array ensures that effect is only run on mount and unmount | |
| return keyPressed | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment