<?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: Andrey Okonetchnikov</title>
    <description>The latest articles on DEV Community by Andrey Okonetchnikov (@okonetchnikov).</description>
    <link>https://dev.to/okonetchnikov</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%2F25315%2F96563e0f-7acc-4d6c-a6e1-41d55df27fdc.jpg</url>
      <title>DEV Community: Andrey Okonetchnikov</title>
      <link>https://dev.to/okonetchnikov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/okonetchnikov"/>
    <language>en</language>
    <item>
      <title>Before you useState</title>
      <dc:creator>Andrey Okonetchnikov</dc:creator>
      <pubDate>Fri, 11 Jun 2021 08:14:00 +0000</pubDate>
      <link>https://dev.to/okonetchnikov/before-you-usestate-1599</link>
      <guid>https://dev.to/okonetchnikov/before-you-usestate-1599</guid>
      <description>&lt;p&gt;Imagine, you are on this amazing website that has lots of filters and you just nailed down a combination that yields perfect results and you would like to share it with your partner. You hit the "Share" button and send it over. Then the other person opens it only to see... the default page instead of filtered results. &lt;em&gt;Everyone hates it!&lt;/em&gt; Yet we, Frontend developers, are the ones who screwed up by treating our applications' state as something that only belongs to the application and burring it in &lt;code&gt;useState&lt;/code&gt; calls or in the Redux store. Luckily, we are the ones who can fix it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Simply &lt;code&gt;useState&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;While implementing a filter for a list of items based on a user input, most of you would probably do something like without even thinking twice (at least I did so many times!):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Apple&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="s2"&gt;Banana&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="s2"&gt;Cherry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// set the initial state&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;option&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;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// filter results using the state&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;setQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// update the state based on the new value&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codesandbox.io/s/before-usestate-1-i7sys"&gt;Open on CodeSandbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This does the job and gives you the user interface we wanted but &lt;em&gt;the state is now not accessible by the user&lt;/em&gt;. You can't share the URL with another person and they won't be able to see what you saw. &lt;/p&gt;

&lt;h2&gt;
  
  
  Sharing the state with the user
&lt;/h2&gt;

&lt;p&gt;People start using your UI and get annoyed by the fact links aren't sharable. So you decide to implement this feature on top of the existing code base. It will probably will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Apple&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="s2"&gt;Banana&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="s2"&gt;Cherry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// get query string from the location&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&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="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// set the initial state to it&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;option&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;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// filter results using the state&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;setQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// update the state based on the new value&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codesandbox.io/s/before-usestate-2-k7non"&gt;Open on CodeSandbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Better! We can parse the URL and set the application state to reflect it but it actually doesn't update the URL as you change the input's value while typing. Let's fix it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Reacting to the user input
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Apple&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="s2"&gt;Banana&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="s2"&gt;Cherry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// get query string from the location&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setQuery&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&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="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// set the initial state to it&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;option&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;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// filter results using the state&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;setQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// update the state based on the new value&lt;/span&gt;

  &lt;span class="c1"&gt;// Now that we have the new state, let's sync it with location&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useEffect&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="c1"&gt;// Calculate new URL based on the state&lt;/span&gt;
    &lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Update the URL in the location&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pushState&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newURL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&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="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codesandbox.io/s/before-usestate-3-jv118"&gt;Open on CodeSandbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Phew! It works but look at that code! But wait, maybe &lt;em&gt;we could do better&lt;/em&gt;? &lt;/p&gt;

&lt;h2&gt;
  
  
  Use URL instead of &lt;code&gt;useState&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Think about what we're trying to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Derive the state from the URL&lt;/li&gt;
&lt;li&gt;Set it as a default value of the &lt;code&gt;useState&lt;/code&gt; call&lt;/li&gt;
&lt;li&gt;Update the React's state in the &lt;code&gt;onChange&lt;/code&gt; event handler using the setter function&lt;/li&gt;
&lt;li&gt;Derive the new URL in the &lt;code&gt;useEffect&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Set the &lt;code&gt;location&lt;/code&gt; to the new URL so it's in sync with the UI&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What if we would treat the URL as &lt;em&gt;our state container?&lt;/em&gt; This way we could bypass the local state completely. Here is the updated algorithm.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Derive the state from the URL&lt;/li&gt;
&lt;li&gt;Update the &lt;code&gt;location&lt;/code&gt; in &lt;code&gt;onChange&lt;/code&gt; callback to keep it in sync with the UI
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;navigate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@reach/router&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Apple&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="s2"&gt;Banana&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="s2"&gt;Cherry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// get query string from the location&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&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="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// get the query value&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;option&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;option&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// filter results using the state&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;queryParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// update the state based on the new value&lt;/span&gt;
    &lt;span class="c1"&gt;// Calculate new URL based on the state&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Update the URL in the location&lt;/span&gt;
    &lt;span class="nx"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newURL&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="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;result&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://codesandbox.io/s/before-usestate-4-zu9ph"&gt;Open on CodeSandbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Much simpler! But most importantly, not only we improved our code, but also we made our application more accessible: each filter result is now sharable using a simple link!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final result
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/embed/before-usestate-3-jv118?autoresize=1&amp;amp;codemirror=1&amp;amp;fontsize=16&amp;amp;module=%2Fsrc%2FApp.js&amp;amp;theme=dark"&gt;https://codesandbox.io/embed/before-usestate-3-jv118?autoresize=1&amp;amp;codemirror=1&amp;amp;fontsize=16&amp;amp;module=%2Fsrc%2FApp.js&amp;amp;theme=dark&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotchas
&lt;/h2&gt;

&lt;p&gt;There are a few gotchas I've discovered while implementing my state this way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Although browsers' &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/History"&gt;native History API&lt;/a&gt; gives a simple way of modifying the state &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API/Working_with_the_History_API"&gt;using &lt;code&gt;pushState()&lt;/code&gt;&lt;/a&gt;, it won't trigger a re-render of the React app. That's why in my last example I use &lt;a href="https://reach.tech/router/"&gt;@reach/router&lt;/a&gt;. Since most popular React frameworks like &lt;a href="https://nextjs.org/docs/api-reference/next/router#userouter"&gt;Next.js&lt;/a&gt; or &lt;a href="https://www.gatsbyjs.com/docs/reach-router-and-gatsby/"&gt;Gatsby&lt;/a&gt; already have a router as a dependency, I don't consider this a problem.&lt;/li&gt;
&lt;li&gt;Second problem is: updating the &lt;code&gt;location&lt;/code&gt; via a router will scroll the page to the top by default in most browsers. Most of the time it shouldn't be a problem since this is desired to see top results. Depending on the layout of the page and device's resolution, though, it can be annoying. In this case there are ways of disabling it:&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Prevent scroll in Next.js
&lt;/h3&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;handleChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;scroll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;shallow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prevent scroll in Gatsby
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shouldUpdateScroll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;routerProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;location&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="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="c1"&gt;// Scroll to top only when we're not searching&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Last but not least: changing the URL will re-render the whole application which can cause some performance problems for bigger and more complex applications. In this case, synchronizing the URL with the state is the only solution for now. With the concurrent mode, though, it might become much less of a problem and that's how I think frameworks should deal with complexity: developers should write the most idiomatic code and let frameworks do optimizations under the hood.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Next time, before you &lt;code&gt;useState&lt;/code&gt;, stop for a second and think about your state. Most applications' state deserves to be shared with your users, so treat it as something public and put it into URL from the beginning. It will make your app more accessible and easy to use and it will make the code much simpler. A win-win situation! &lt;/p&gt;

&lt;p&gt;P.S.: Even if you can't implement the final solution for some reason now, I still encourage you to think about the URL as an additional user interface to interact with the website and expose as much as possible to allow such interactions.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>NetlifyCMS with GitHub OAuth authentication hosted on Vercel</title>
      <dc:creator>Andrey Okonetchnikov</dc:creator>
      <pubDate>Sun, 23 May 2021 20:05:53 +0000</pubDate>
      <link>https://dev.to/okonetchnikov/netlifycms-with-github-oauth-authentication-hosted-on-vercel-3309</link>
      <guid>https://dev.to/okonetchnikov/netlifycms-with-github-oauth-authentication-hosted-on-vercel-3309</guid>
      <description>&lt;p&gt;Recently, I was moving &lt;a href="http://www.danielamulle.at"&gt;www.danielamulle.at&lt;/a&gt; to Vercel while transitioning to Next.js from Gatsby. The transition went quite smooth in general, but one thing I didn't expect troubles with was  making NetlifyCMS work on Vercel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.netlifycms.org"&gt;NetlifyCMS&lt;/a&gt; is a great headless content management system that has good defaults, is flexible enough to fulfill most needs, has a pluggable API, and works well if you host your content on GitHub. &lt;a href="https://github.com/netlify/netlify-cms/graphs/contributors"&gt;I have also contributed&lt;/a&gt; to the project when it was at the very early stage. For obvious reasons, Netlify CMS works really well when you host on Netlify but unfortunately things become a bit more complicated if you decide to move to another hosting provider.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is due to a requirement of GitHub’s authentication flow. To use a GitHub backend with NetlifyCMS, you have to run your own server to handle OAuth or use serverless provider like Vercel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Netlify substitutes the need for the server and makes it work out-of-the-box but it also might feel like a verndor lock-in. Fortunately, there are open source solutions that implement everything needed but setting everything up can take some time. This is a step-by-step guide of things that worked for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1. Configure Netlify CMS
&lt;/h2&gt;

&lt;p&gt;Put you &lt;code&gt;config.yml&lt;/code&gt; file to &lt;code&gt;/public&lt;/code&gt; so it's accessible by NetlifyCMS when deployed to production. Open the file and additionally to your existing config you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set &lt;code&gt;repo&lt;/code&gt; to your GitHub repo that contains the source code of your site.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;base_url&lt;/code&gt; to the production domain with HTTPS protocol, for example, &lt;code&gt;https://www.danielamulle.at&lt;/code&gt; in my case.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;auth_endpoint: api/auth&lt;/code&gt;. This is the URL that NetlifyCMS will open when you click "Authenticate" button. We'll implement this endpoint in our next.js app later.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I've also enabled &lt;code&gt;local_backend: true&lt;/code&gt; in the config to make CMS work with the local git without going over the server when in development mode. You can read about &lt;a href="https://www.netlifycms.org/docs/beta-features/#working-with-a-local-git-repository"&gt;making NetlifyCMS to work with a local git repository&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2. Create GitHub App
&lt;/h2&gt;

&lt;p&gt;Go to GitHub and navigate to Settings → Developer settings → GitHub Apps → New GitHub App or use this &lt;a href="https://github.com/settings/apps/new"&gt;direct link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's not important how you'll name the app since it will not be published. Fill &lt;code&gt;User authorization callback URL&lt;/code&gt; with the URL &lt;code&gt;https://&amp;lt;domain&amp;gt;/api/callback&lt;/code&gt;. Use &lt;em&gt;exactly the URL&lt;/em&gt; that you entered as  &lt;code&gt;base_url&lt;/code&gt; at the previous step.&lt;/p&gt;

&lt;p&gt;Disable Webhook checkbox and set permissions to &lt;code&gt;Read &amp;amp; Write&lt;/code&gt; for "Contents":&lt;/p&gt;

&lt;p&gt;Hit "Create app" and on the next page you'll see the app details with &lt;code&gt;Client ID&lt;/code&gt; and &lt;code&gt;Client secret&lt;/code&gt;. We will need those on the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3. Set environment secrets
&lt;/h2&gt;

&lt;p&gt;Add those values to Vercel environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vercel &lt;span class="nb"&gt;env &lt;/span&gt;add secret OAUTH_CLIENT_ID &amp;lt;client-id-of-GitHub-App&amp;gt;
vercel &lt;span class="nb"&gt;env &lt;/span&gt;add secret OAUTH_CLIENT_SECRET &amp;lt;client-secret-of-GitHub-App&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4. Setup OAuth client in Next.js app
&lt;/h2&gt;

&lt;p&gt;Install &lt;a href="https://github.com/bericp1/netlify-cms-oauth-provider-node"&gt;https://github.com/bericp1/netlify-cms-oauth-provider-node&lt;/a&gt; as a dependency to your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;netlify-cms-oauth-provider-node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and create a &lt;code&gt;.env&lt;/code&gt; file to add following configuration options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;OAUTH_CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;OAUTH_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="nv"&gt;COMPLETE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://&amp;lt;domain&amp;gt;/api/callback
&lt;span class="nv"&gt;ORIGIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;domain&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;&amp;lt;domain&amp;gt;&lt;/code&gt; is your domain without https. It's important to match &lt;code&gt;COMPLETE_URL&lt;/code&gt; here and in the GitHub App so make sure they are the same.&lt;/p&gt;

&lt;p&gt;Then create 2 files: &lt;code&gt;/src/pages/api/auth.js&lt;/code&gt; and &lt;code&gt;/src/pages/api/callback.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createVercelBeginHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;netlify-cms-oauth-provider-node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createVercelBeginHandler&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;useEnv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createVercelCompleteHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;netlify-cms-oauth-provider-node&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createVercelCompleteHandler&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;useEnv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, push the code to production branch on Vercel and wait till it's deployed. Navigate to your site and go to the CMS URL. You should be able to authenticate with GitHub now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;Huge thanks to @bericp1 for &lt;a href="https://github.com/bericp1/netlify-cms-oauth-provider-node"&gt;https://github.com/bericp1/netlify-cms-oauth-provider-node&lt;/a&gt; and &lt;a class="mentioned-user" href="https://dev.to/robinpokorny"&gt;@robinpokorny&lt;/a&gt;
 for &lt;a href="https://github.com/robinpokorny/netlify-cms-now"&gt;https://github.com/robinpokorny/netlify-cms-now&lt;/a&gt;. Robin's solution didn't work for me but it led me to the right direction.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>netlifycms</category>
      <category>vercel</category>
      <category>github</category>
    </item>
    <item>
      <title>Running Node.js natively on Apple Silicon</title>
      <dc:creator>Andrey Okonetchnikov</dc:creator>
      <pubDate>Thu, 14 Jan 2021 21:35:55 +0000</pubDate>
      <link>https://dev.to/okonetchnikov/running-node-js-natively-on-apple-silicon-5d3j</link>
      <guid>https://dev.to/okonetchnikov/running-node-js-natively-on-apple-silicon-5d3j</guid>
      <description>&lt;p&gt;I just got the one of the newest M1-based MacBooks and I wanted to get it up and running as fast as possible so I went with the Migration Assistant and migrated everything from my old MacBook Pro 2017 running macOS 10. To my surprise it worked without &lt;em&gt;any&lt;/em&gt; issues at all (I would expect at least it requires same OS versions).&lt;/p&gt;

&lt;p&gt;Although it already felt much faster than my previous machine even running most of the software through Rosetta 2 emulation mode, I was still curious: how much faster it actually is when running things natively. &lt;/p&gt;

&lt;p&gt;Since the existing Homebrew installation wouldn't allow my updating or installing packages anymore because of more restrictive OS permissions, I was faced with "update the x86 homebrew" or “use an experimental cutting-edge ARM build”. I went with the latter and this post summarizes my experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 0. Remove x86 zsh binary
&lt;/h2&gt;

&lt;p&gt;One of the biggest confusion for me was the fact my shell would not run in arm64 mode. This was caused by the fact I already have been using zsh shell before and it was migrated over. The new macOS Big Sur comes with zsh as a default shell so you don’t need to install it separately anymore.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/okonetchnikov/status/1343140569430822914" rel="noopener noreferrer"&gt;https://twitter.com/okonetchnikov/status/1343140569430822914&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To solve this issue I had to remove x86 compiled zsh that I installed via Homebrew. This cannot be done with &lt;code&gt;brew remove&lt;/code&gt; since Homebrew won’t have enough permissions but you can remove zsh manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// 1. verify you&lt;span class="s1"&gt;'re not running native zsh

which zsh

// 2. if it is different from /bin/zsh, run

rm "$(which zsh)"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify by opening a new terminal session and running &lt;code&gt;arch&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜ &lt;span class="nb"&gt;arch
&lt;/span&gt;arm64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1. Install Apple Silicon version of the Homebrew
&lt;/h2&gt;

&lt;p&gt;To install the ARM version of Homebrew on the Apple Silicon Mac, I used the manual "untar anywhere" method: &lt;a href="https://docs.brew.sh/Installation#untar-anywhere" rel="noopener noreferrer"&gt;https://docs.brew.sh/Installation#untar-anywhere&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Starting from version 2.7.1, Homebrew supports Apple Silicon out-of-the-box.&lt;/p&gt;

&lt;p&gt;This method allows installing Homebrew alongside with the x86 version which is probably a good idea for a time being since not all packages are yet pre-built for ARM. I had a few issues while building from sources, too. &lt;/p&gt;

&lt;p&gt;After installing Homebrew into separate directory, add the following to your &lt;code&gt;.zshrc&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Support for two Homebrew installations&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/opt/homebrew/bin:/usr/local/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;ibrew&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'arch -x86_64 /usr/local/bin/brew'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that you can use both arm64 and x86 installations of Homebrew side-by-side.&lt;/p&gt;

&lt;p&gt;For more information on Homebrew compatibility on Apple Silicon check out &lt;a href="https://github.com/mikelxc/Workarounds-for-ARM-mac" rel="noopener noreferrer"&gt;https://github.com/mikelxc/Workarounds-for-ARM-mac&lt;/a&gt; and &lt;a href="https://soffes.blog/homebrew-on-apple-silicon" rel="noopener noreferrer"&gt;https://soffes.blog/homebrew-on-apple-silicon&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2. Install node and yarn
&lt;/h2&gt;

&lt;p&gt;After you have installed Homebrew, install node (which includes npm) normally running  &lt;code&gt;brew install node&lt;/code&gt; Install Yarn using &lt;code&gt;brew install yarn&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To verify that you're running the Node in ARM architecture, enable the row "Architecture" in Activity Monitor,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwcn7v36xmy8hh3ygh8zh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwcn7v36xmy8hh3ygh8zh.png" alt="Screenshot of Activity Monitor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enable "Architecture" column with the right-click on the header. If node processes say "Apple" you're running them natively!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3. Install packages to run Gatsby
&lt;/h2&gt;

&lt;p&gt;After running Node natively I had issues running Gatsby project. While doing &lt;code&gt;npm install&lt;/code&gt; in the Gatsby project, it will fail because of the binding for the Sharp — a native C library Gatsby using — needs to be compiled under the ARM architecture. It didn't work out of the box for me since some native packages were missing. I was able to resolve it following this GitHub issue &lt;a href="https://github.com/lovell/sharp/issues/2460" rel="noopener noreferrer"&gt;https://github.com/lovell/sharp/issues/2460&lt;/a&gt; and doing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/gatsby-project
brew &lt;span class="nb"&gt;install &lt;/span&gt;vips
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; node_modules
npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that the installation went well and I could run the project. There were no issues whatsoever running other JavaScript projects (using TypeScript or Bable).&lt;/p&gt;

&lt;h2&gt;
  
  
  So, how much faster is ARM Node compared to x86
&lt;/h2&gt;

&lt;p&gt;I ran a few tests on the same machine and also compared build speeds with my previous MacBook Pro 2017 that has 2,9 GHz i7 Quad Core CPU and 16 GB of RAM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgjx10z87qbk3k6t5jlzq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgjx10z87qbk3k6t5jlzq.jpg" alt="Building the Next.js for https://www.monolisa.dev takes 10 seconds in arm64 Node"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Building the Next.js for &lt;a href="https://www.monolisa.dev" rel="noopener noreferrer"&gt;https://www.monolisa.dev&lt;/a&gt; takes 10 seconds in arm64 Node&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd94t8p7wmqo37gttxqm4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd94t8p7wmqo37gttxqm4.jpg" alt="vs. 17 seconds when using Rosetta2 emulation and x86 Node"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;vs. 17 seconds when using Rosetta2 emulation and x86 Node.&lt;/p&gt;

&lt;p&gt;The results were... astonishing! &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Running x86 vs arm64 node resulted in a ~40% improvement. Building a  Gatsby site with a few dozens of pages went from 55 seconds on MacBook Pro to 15 seconds on MacBook Air!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's not forget, MacBook Air is a fan-less machine that you can put on your lap without a risk of getting a skin burn. And my old computer was making noises similar to an airplane taking off 🤦‍♂️.&lt;/p&gt;

&lt;p&gt;Here is the related Twitter thread: &lt;a href="https://twitter.com/okonetchnikov/status/1346162117506985985" rel="noopener noreferrer"&gt;https://twitter.com/okonetchnikov/status/1346162117506985985&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;I still didn't finish this, but I'd like to try cleaning up previous installation of Homebrew completely and move everything to &lt;code&gt;/opt/homebrew&lt;/code&gt; and also try installing only native packages. It didn't work for me for &lt;a href="https://github.com/Schniz/fnm" rel="noopener noreferrer"&gt;fnm&lt;/a&gt; that I'm using to manage node versions meaning if I install a different node version over it it will use x86 build again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating installation
&lt;/h2&gt;

&lt;p&gt;In order to save time in the future, I have a collection of scripts that automate the process of setting up a new computer. You can find them onGitHub &lt;a href="https://github.com/okonet/dotfiles" rel="noopener noreferrer"&gt;https://github.com/okonet/dotfiles&lt;/a&gt;. I've updated it accordingly so it should work on M1 Macs. Use it your own risk and please report issues and send PRs if you decide to use those scripts.&lt;/p&gt;

</description>
      <category>applem1</category>
      <category>performance</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Hi, I'm Andrey Okonetchnikov</title>
      <dc:creator>Andrey Okonetchnikov</dc:creator>
      <pubDate>Tue, 18 Jul 2017 09:08:21 +0000</pubDate>
      <link>https://dev.to/okonetchnikov/hi-im-andrey-okonetchnikov</link>
      <guid>https://dev.to/okonetchnikov/hi-im-andrey-okonetchnikov</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3h0teru8qie8vfqjwxsf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3h0teru8qie8vfqjwxsf.jpg" width="474" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m a Front End Engineer and UI &amp;amp; UX Designer from Russia living in Vienna, Austria and currently I work for &lt;a href="https://feedly.com" rel="noopener noreferrer"&gt;Feedly&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I’m passionate about programming, UI and UX design, typography, music, photography, mountain biking and coffee.&lt;/p&gt;

&lt;p&gt;I’m an engineer with a Master’s degree in Computer Science, but I’m also a designer. I love solving complex problems, no matter if it’s a design or technical challenge. I mostly design in code using JavaScript and CSS, but when it’s required I use graphic editors as well.&lt;/p&gt;

&lt;p&gt;I believe that “No UI == Best UI” and that good UI is how things work and not just how they look. I value statistics and tend to verify my ideas using prototypes and usability tests.&lt;/p&gt;

&lt;p&gt;I care about code readability and maintainability. I’m the author of ðŸš«ðŸ’© &lt;a href="https://github.com/okonet/lint-staged" rel="noopener noreferrer"&gt;lint-staged&lt;/a&gt; – a simple tool that helps improve the code quality in teams.&lt;/p&gt;

&lt;p&gt;When writing styles, I use CSS-modules or, when not possible, BEM and I believe that CSS-in-JS is the future of CSS.&lt;/p&gt;

&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/okonetchnikov" rel="noopener noreferrer"&gt;@okonetchnikov&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
