DEV Community

loading...
Cover image for Having fun with React Hooks

Having fun with React Hooks

chrisfeist profile image Chris Feist ・2 min read

I was recently tasked with creating an Easter Egg in our application to launch a troubleshooting menu. In the past, I've done this by clicking on a sequence of items or on what appears to be a disabled icon a few times. However, this time I decided to try a different approach and implement a React hook that listens for the Konami Code input on the keyboard. Thus, the useKonami hook was born.

Here are the highlights:

  • A hook that listens for a keyboard sequence (default is the Konami Code) on the window or a target element, and then calls an onUnlock callback after the sequence has been successfully entered by the user
  • Zero external dependencies
  • Built using standard React Hooks API's
  • Optimized to avoid unnecessary rerenders
  • Open source on GitHub

How does it work?

The hook uses React's useEffect hook to register and unregister a keydown event listener on the window or supplied target element. It then receives the keyboard down presses and compares them against the unlock sequence. Upon successfully pressing the sequence, the hook then calls the supplied onUnlock callback. If the sequence is entered incorrectly, then the optional onReset callback will be called. There is also an optional onKeyPress callback that is invoked each time a key in the sequence is successfully pressed.

How is it optimized?

A good hook implementation shouldn't expect that the user is going to wrap their callbacks with React's useCallback hook. Since the keyboard event listener isn't dependent on the supplied callback changes, the callbacks are stored in a mutable variable using React's useRef hook. This avoids unnecessary re-renders and registering/unregistering of the keyboard event listener.

It should also be expected that a user may define their structured objects inline with the hook call as well. Therefore, the same approach was taken for a custom unlock sequence. Both of these optimizations would guard against the following example:

const MyUnlockableComponent = () => {
  useKonamiCode({
    // Callback defined inline
    onUnlock: () => console.log('UNLOCKED'),
    // Structured data defined in render function
    sequence: ['x', 'y', 'z', 'z', 'y'],
  });

  return (<div>You can't unlock me!</div>);
}
Enter fullscreen mode Exit fullscreen mode

Any other goodies?


Thanks for reading my post and feel free to leave feedback here or in the GitHub repo!

Discussion (0)

pic
Editor guide