<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chris Feist</title>
    <description>The latest articles on DEV Community by Chris Feist (@chrisfeist).</description>
    <link>https://dev.to/chrisfeist</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F346926%2Ff8bdb9e1-e533-4cae-851e-9820abbfa29f.png</url>
      <title>DEV Community: Chris Feist</title>
      <link>https://dev.to/chrisfeist</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chrisfeist"/>
    <language>en</language>
    <item>
      <title>Having fun with React Hooks</title>
      <dc:creator>Chris Feist</dc:creator>
      <pubDate>Tue, 23 Mar 2021 03:51:19 +0000</pubDate>
      <link>https://dev.to/chrisfeist/having-fun-with-react-hooks-230n</link>
      <guid>https://dev.to/chrisfeist/having-fun-with-react-hooks-230n</guid>
      <description>&lt;p&gt;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 &lt;a href="https://en.wikipedia.org/wiki/Konami_Code"&gt;Konami Code&lt;/a&gt; input on the keyboard. Thus, the &lt;a href="https://www.npmjs.com/package/use-konami"&gt;&lt;code&gt;useKonami&lt;/code&gt;&lt;/a&gt; hook was born.&lt;/p&gt;

&lt;p&gt;Here are the highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;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&lt;/li&gt;
&lt;li&gt;Zero external dependencies&lt;/li&gt;
&lt;li&gt;Built using standard React Hooks API's&lt;/li&gt;
&lt;li&gt;Optimized to avoid unnecessary rerenders&lt;/li&gt;
&lt;li&gt;Open source on &lt;a href="https://github.com/chris-feist/use-konami"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How does it work?
&lt;/h3&gt;

&lt;p&gt;The hook uses React's &lt;a href="https://reactjs.org/docs/hooks-reference.html#useeffect"&gt;&lt;code&gt;useEffect&lt;/code&gt;&lt;/a&gt; hook to register and unregister a &lt;code&gt;keydown&lt;/code&gt; 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 &lt;code&gt;onUnlock&lt;/code&gt; callback. If the sequence is entered incorrectly, then the optional &lt;code&gt;onReset&lt;/code&gt; callback will be called. There is also an optional &lt;code&gt;onKeyPress&lt;/code&gt; callback that is invoked each time a key in the sequence is successfully pressed.&lt;/p&gt;

&lt;h3&gt;
  
  
  How is it optimized?
&lt;/h3&gt;

&lt;p&gt;A good hook implementation shouldn't expect that the user is going to wrap their callbacks with React's &lt;a href="https://reactjs.org/docs/hooks-reference.html#usecallback"&gt;&lt;code&gt;useCallback&lt;/code&gt;&lt;/a&gt; hook. Since the keyboard event listener isn't dependent on the supplied callback changes, &lt;a href="https://github.com/chris-feist/use-konami/blob/4161ad60adab9c6e757500d1960a661c4b77ade3/src/index.ts#L70"&gt;the callbacks are stored&lt;/a&gt; in a mutable variable using React's &lt;a href="https://reactjs.org/docs/hooks-reference.html#useref"&gt;&lt;code&gt;useRef&lt;/code&gt;&lt;/a&gt; hook. This avoids unnecessary re-renders and registering/unregistering of the keyboard event listener.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://github.com/chris-feist/use-konami/blob/4161ad60adab9c6e757500d1960a661c4b77ade3/src/index.ts#L68"&gt;custom unlock sequence&lt;/a&gt;. Both of these optimizations would guard against the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyUnlockableComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;useKonamiCode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// Callback defined inline&lt;/span&gt;
    &lt;span class="na"&gt;onUnlock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UNLOCKED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;// Structured data defined in render function&lt;/span&gt;
    &lt;span class="na"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;y&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;y&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;You&lt;/span&gt; &lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;t unlock me!&amp;lt;/div&amp;gt;);
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Any other goodies?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Fully typed codebase using TypeScript&lt;/li&gt;
&lt;li&gt;Fully &lt;a href="https://github.com/chris-feist/use-konami/blob/main/README.md"&gt;documented&lt;/a&gt; API and repository&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chris-feist.github.io/use-konami/"&gt;Storybook examples available&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://travis-ci.com/chris-feist/use-konami"&gt;Continuous Integration&lt;/a&gt; with &lt;a href="https://app.codecov.io/gh/chris-feist/use-konami"&gt;100% Test Coverage&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks for reading my post and feel free to leave feedback here or in the &lt;a href="https://github.com/chris-feist/use-konami"&gt;GitHub repo&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
