<?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: Avi Aryan</title>
    <description>The latest articles on DEV Community by Avi Aryan (@aviaryan).</description>
    <link>https://dev.to/aviaryan</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%2F24983%2F9ec9bf32-1dfd-4a6b-b377-5682bbf86dce.jpg</url>
      <title>DEV Community: Avi Aryan</title>
      <link>https://dev.to/aviaryan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aviaryan"/>
    <language>en</language>
    <item>
      <title>What do I learn today to get a dev job?</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Thu, 21 May 2020 07:52:52 +0000</pubDate>
      <link>https://dev.to/aviaryan/what-do-i-learn-today-to-get-a-dev-job-3kbi</link>
      <guid>https://dev.to/aviaryan/what-do-i-learn-today-to-get-a-dev-job-3kbi</guid>
      <description>&lt;p&gt;What do I learn today to get a dev job?&lt;/p&gt;

&lt;p&gt;Believe it or not, JavaScript and React are still the first things I would learn if I was starting from scratch.&lt;/p&gt;

&lt;p&gt;One could say - “JS and React have had a BOOM period for some time. They will come back to the ground soon.”&lt;/p&gt;

&lt;p&gt;But that’s not true. Both JS and React ecosystems keep on innovating.&lt;/p&gt;

&lt;p&gt;Recently, Microsoft launched React Native for MacOS.&lt;/p&gt;

&lt;p&gt;This might change the field of MacOS development, and a good chunk of Swift or Electron apps will be written in React Native.&lt;/p&gt;

&lt;p&gt;The React team recently launched Suspense and before that Hooks which are game-changers in UI development.&lt;/p&gt;

&lt;p&gt;JS is not behind too. Both the ECMA and the Node team keep on releasing new versions and specifications regularly.&lt;/p&gt;

&lt;p&gt;Recently Deno launched which is a new runtime for JS and TS.&lt;/p&gt;

&lt;p&gt;Also, the wide-adoption of TypeScript is helping JavaScript “haters”, programmers that despise loose-typing (Java, C#, Go programmers) to use JavaScript.&lt;/p&gt;

&lt;p&gt;Overall, the future of React and JS looks bright for at least the next 3 years, if not more.&lt;/p&gt;

&lt;p&gt;So you can confidently start or change your career on this stack.&lt;/p&gt;




&lt;p&gt;This article was first posted on &lt;a href="https://aviaryan.com/logs/learn-JS-for-job"&gt;my blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>job</category>
    </item>
    <item>
      <title>How to start contributing to open-source for experienced devs</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Fri, 15 May 2020 10:08:18 +0000</pubDate>
      <link>https://dev.to/aviaryan/how-to-start-contributing-to-open-source-for-experienced-devs-39a8</link>
      <guid>https://dev.to/aviaryan/how-to-start-contributing-to-open-source-for-experienced-devs-39a8</guid>
      <description>&lt;p&gt;I got this question in my DM yesterday so here’s how I do it.&lt;/p&gt;

&lt;p&gt;(1) Contribute to something you use.&lt;/p&gt;

&lt;p&gt;If you have been a dev for some time, chances are you are using many things open source. Eg - youtube-dl, NextJS, ReactJS, Prettier.&lt;/p&gt;

&lt;p&gt;Even things that are not open source can have open-source components. Eg - Firebase.&lt;/p&gt;

&lt;p&gt;Deciding to contribute to something you use ensures you have the background knowledge and the motivation to do the contribution.&lt;/p&gt;

&lt;p&gt;An open-source contribution is a challenging process so this is important.&lt;/p&gt;

&lt;p&gt;(2) Look into issues, pick one that excites you&lt;/p&gt;

&lt;p&gt;Popular projects have tons of issues. Pick one that you understand and think you can do.&lt;/p&gt;

&lt;p&gt;Don’t be ashamed if it’s an easy issue. All contributions matter.&lt;/p&gt;

&lt;p&gt;(3) Clone the codebase, understand it and then do the fix&lt;/p&gt;

&lt;p&gt;Don’t worry if understanding the codebase takes time. It is expected to take time.&lt;/p&gt;

&lt;p&gt;(4) Finally, send a PR&lt;/p&gt;

&lt;p&gt;Your PR may not get merged in a day or two. This is normal.&lt;/p&gt;

&lt;p&gt;Project maintainers are busy and have a backlog of PRs.&lt;/p&gt;

&lt;p&gt;Gently remind them after a week.&lt;/p&gt;

&lt;p&gt;Follow through their feedback, and soon you will have your PR merged.&lt;/p&gt;




&lt;p&gt;This was first posted on &lt;a href="https://www.linkedin.com/in/aviaryan/"&gt;my LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why you should do ethical hacking anyway?</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Sun, 05 Apr 2020 10:33:52 +0000</pubDate>
      <link>https://dev.to/aviaryan/why-you-should-do-ethical-hacking-anyway-2man</link>
      <guid>https://dev.to/aviaryan/why-you-should-do-ethical-hacking-anyway-2man</guid>
      <description>&lt;p&gt;I was looking into ethical hacking as I was interested in CyberSec and was looking for a practical way to get in.&lt;/p&gt;

&lt;p&gt;After some reading and playing around, I see its potential.&lt;/p&gt;

&lt;p&gt;It’s a great field to apply concepts from various domains of software development.&lt;/p&gt;

&lt;p&gt;Here is what I had to use in only 2 days of doing ethical hacking on HackThisSite.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;HTTP (Protocol Knowledge)&lt;/li&gt;
&lt;li&gt;Backend&lt;/li&gt;
&lt;li&gt;Common Software Development Patterns&lt;/li&gt;
&lt;li&gt;SQL&lt;/li&gt;
&lt;li&gt;Web servers (Apache, Nginx)&lt;/li&gt;
&lt;li&gt;Thinking like a Notorious Hacker&lt;/li&gt;
&lt;li&gt;Street Smarts&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can see, ethical hacking requires using knowledge from various spectrum of software development to get work done.&lt;/p&gt;

&lt;p&gt;In other words, it’s extremely practical.&lt;/p&gt;

&lt;p&gt;I would recommend everyone to try it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Google “OWASP Top 10” and learn the concepts mentioned there. &lt;/li&gt;
&lt;li&gt;Then, create an account on HackThisSite(dot)org and try solving the challenges.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>hacking</category>
    </item>
    <item>
      <title>Rendering JSON-LD data in NextJS and ReactJS</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Thu, 05 Mar 2020 12:28:03 +0000</pubDate>
      <link>https://dev.to/aviaryan/rendering-json-ld-data-in-nextjs-and-reactjs-29op</link>
      <guid>https://dev.to/aviaryan/rendering-json-ld-data-in-nextjs-and-reactjs-29op</guid>
      <description>&lt;p&gt;Rendering JSON-LD data in NextJS and ReactJS is quite straight-forward. Here are the steps involved.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Organize data in a plain JavaScript Object.&lt;/li&gt;
&lt;li&gt;Serialize it using &lt;code&gt;JSON.stringify&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Include the data in the &lt;code&gt;script&lt;/code&gt; tag using &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Optional but recommended - Attach a key. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first step is creating the JSON Object. I used this in &lt;a href="http://goremote.in/"&gt;GoRemote&lt;/a&gt; which is a job-listing site. Here is the function which creates a job schema given the &lt;code&gt;job&lt;/code&gt; object. It returns a simple JavaScript object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;makeJobSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&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;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stripHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&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="c1"&gt;// schema truncated for brevity&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@context&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;http://schema.org&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;@type&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;JobPosting&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;datePosted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;company&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;workHours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Flexible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;validThrough&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;addDaysToDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;hiringOrganization&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;@type&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;Organization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;company&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;sameAs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;company&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;website&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;logo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;company&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logo&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;p&gt;The next step is to serialize this object using &lt;code&gt;JSON.stringify&lt;/code&gt;. Once serialized, we insert it in a  &lt;code&gt;script&lt;/code&gt; tag using &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt;.  Here is how the code looks like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&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;JobSchema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;job&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;&lt;/span&gt;&lt;span class="nt"&gt;script&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="s2"&gt;`jobJSON-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&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;'application/ld+json'&lt;/span&gt;
            &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;makeJobSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&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;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;Now, you might question, why do we use &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt;? Why not insert the serialized object as a string? Because if we do that, React treats it as HTML and so HTML-escapes the text. The output then looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;@&lt;/span&gt;&lt;span class="nd"&gt;context&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;:&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;quot&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nl"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:...&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This won’t work with bots that will crawl the page for this metadata. In other words, we don’t want to HTML-escape the text within these &lt;code&gt;script&lt;/code&gt; tags. So, that’s why we use &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another question would be why do you need to add a &lt;code&gt;key&lt;/code&gt;? It’s not needed but it’s a good-to-have to avoid the situation where you have multiple JSON-LD’s for a single entity. A &lt;code&gt;key&lt;/code&gt; makes sure that only one such instance is included in the rendered page.&lt;/p&gt;

&lt;p&gt;Well, there you have it.&lt;/p&gt;

&lt;p&gt;Once you have the page running, you can use &lt;a href="https://ngrok.com/"&gt;ngrok&lt;/a&gt; to expose your localhost online and Google’s &lt;a href="https://search.google.com/structured-data/testing-tool/u/0/"&gt;structured data testing tool&lt;/a&gt; to make sure everything works as expected. &lt;/p&gt;




&lt;p&gt;This article was posted on &lt;a href="https://aviaryan.com/blog/jsonld-nextjs-react"&gt;Avi Aryan's Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Practical Software Testing Ideas</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Tue, 25 Feb 2020 07:26:45 +0000</pubDate>
      <link>https://dev.to/aviaryan/practical-software-testing-ideas-k5b</link>
      <guid>https://dev.to/aviaryan/practical-software-testing-ideas-k5b</guid>
      <description>&lt;p&gt;Testing is one of the most important practices in software development. And with automated test runners like Travis, there’s no reason not to write tests. &lt;/p&gt;

&lt;p&gt;In this article, I talk about the testing ideas that have helped me in my developer life.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test external dependencies periodically
&lt;/h2&gt;

&lt;p&gt;External APIs can break anytime. They don’t actually "break" but the API you expect it to provide and the API it provides can mismatch anytime. So, you can’t relax while using them.&lt;/p&gt;

&lt;p&gt;One way to reduce this risk is by running tests against them periodically. You can use the cron feature of TravisCI to do so. For example, in &lt;a href="https://goremote.in/"&gt;GoRemote&lt;/a&gt;, I use these tests to make sure that StackOverflow doesn’t “break for me”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test close negative cases as well
&lt;/h2&gt;

&lt;p&gt;Many developers only test the positive cases of a test. That is, this should work like that. But they should test the negative cases as well.  This is especially true when it's quite easy for the tested function to be buggy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;hasUnicodeOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&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="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/¹1️⃣/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;test&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="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;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasUnicodeOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;¹&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBe&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="c1"&gt;// negative test case below&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasUnicodeOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBe&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There’s a chance the above function includes numeric 1 in the regex. So we test the negative case for it to make sure it doesn’t happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  When in doubt, test
&lt;/h2&gt;

&lt;p&gt;Many times you won’t be sure if you want to test that code or not. It might be too trivial. Or you would think you don’t need to check it because it would never happen. In that case, write the test. Writing tests never did any harm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend tests &amp;gt; Frontend tests, usually
&lt;/h2&gt;

&lt;p&gt;Backend tests are usually more important than frontend tests. More so if backend handles all the data manipulation. So make sure to test the backend. If you have limited time to give on tests, prefer backend.&lt;/p&gt;

&lt;p&gt;Yes, I know that we should test everything. But when working on a tight schedule, it can be challenging to justify time writing less critical tests. So this is what you do then.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t delete or comment a test
&lt;/h2&gt;

&lt;p&gt;At times, you might want to delete a test because it isn’t adding value. Or a test failed and you think you don’t need it and so you comment it out. Don’t do that, ever. This starts the bad habit of commenting or removing tests and after a while, your code is left untested. Instead, take the time and fix the test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t leave your project with failing builds
&lt;/h2&gt;

&lt;p&gt;Don’t leave your project with failing tests. It doesn’t matter if the test that is failing is non-critical. Fix it! Now. Otherwise, it will envelop a critical failing test later on. And you won’t know because you will think that it’s the non-critical test that is causing the build to fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try to practice TDD
&lt;/h2&gt;

&lt;p&gt;I recommend TDD. But I know it’s hard to follow when working on a deadline, trying to ship that feature. So yeah, try to do it. But if not, still okay.&lt;/p&gt;

&lt;p&gt;Many a time, I don’t do TDD because I don’t need to run the tests every time to check. I know that the new test will fail and adding this optimized logic to the code will fix it. So I write the finished code and test only in the end instead of testing three times — one fail, one pass, one refactor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use tests as you use insurance
&lt;/h2&gt;

&lt;p&gt;You have insurance for your health, life, and house. Tests are the same. They are insurance for your code. Also, insurance costs money in real life. But software tests usually don’t cost anything. So use it.&lt;/p&gt;

&lt;p&gt;You can say writing tests take time but it prevents you from getting on that Saturday evening call because of a critical bug discovered in production. So I will say the time spent is worth it.&lt;/p&gt;

&lt;p&gt;And it saves money as well since you will lose business if your product is buggy. So, writing tests is value for time and money spent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prefer integration tests over unit tests, when in a bind
&lt;/h2&gt;

&lt;p&gt;Many times, you don’t have the time to test everything. Or you don’t want to. Whatever it is, in that case, prefer integration tests over unit tests. By their nature, they cover a larger surface area of the code. So they have more chance of finding a non-trivial bug. Note that they won’t find all the bugs in your code. Only the outstanding ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t test like a robot
&lt;/h2&gt;

&lt;p&gt;Testing is as much art as science. You need to know what to test. &lt;/p&gt;

&lt;p&gt;Trying to reach 100% coverage will take a lot of time and you may still leave bugs if you don’t know what to test. &lt;/p&gt;

&lt;p&gt;So chill out, put on your creative hat, and write tests that can catch bugs. One way to do this is by starting to notice where you discover bugs in software applications and writing tests to capture those.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;First posted on &lt;a href="https://aviaryan.com/blog/testing-ideas"&gt;my blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>testing</category>
    </item>
    <item>
      <title>Why you should get a good, international domain for yourself</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Fri, 14 Feb 2020 14:23:44 +0000</pubDate>
      <link>https://dev.to/aviaryan/why-you-should-get-a-good-international-domain-for-yourself-30jd</link>
      <guid>https://dev.to/aviaryan/why-you-should-get-a-good-international-domain-for-yourself-30jd</guid>
      <description>&lt;p&gt;I see many new developers and even some senior developers going by a &lt;code&gt;.in&lt;/code&gt; or even a &lt;code&gt;.tk&lt;/code&gt; for their websites.&lt;/p&gt;

&lt;p&gt;But this is short-sighted. Why?&lt;/p&gt;

&lt;p&gt;Because you might move out of India. Or you might work for US and UK companies remotely. In that case, &lt;code&gt;.in&lt;/code&gt; is not the ideal TLD you want for your domain. And &lt;code&gt;.tk&lt;/code&gt; is not even worth a mention. It’s available for free and it doesn’t make a good impression of you.&lt;/p&gt;

&lt;p&gt;Get a &lt;code&gt;.com&lt;/code&gt; if possible. If your name is too common, get a &lt;code&gt;.io&lt;/code&gt; or &lt;code&gt;.tech&lt;/code&gt; or &lt;code&gt;.co&lt;/code&gt; or &lt;code&gt;.net&lt;/code&gt;. Anything less than that is selling yourself short.&lt;/p&gt;

&lt;p&gt;Saving $7/year by getting a &lt;code&gt;.in&lt;/code&gt; instead of a &lt;code&gt;.com&lt;/code&gt; might look like a deal when you are starting as a developer but after a few years, you will regret saving $28 by not getting a &lt;code&gt;.com&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;So do it right whilst you still have time (SEO!) and get a proper domain.&lt;/p&gt;

&lt;p&gt;Otherwise, you will be like me, renewing your &lt;code&gt;.in&lt;/code&gt; domain every year (aviaryan.in) till the end of the universe so that you can permanently redirect its traffic to your &lt;code&gt;.com&lt;/code&gt; domain.&lt;/p&gt;




&lt;p&gt;This article was first posted to &lt;a href="https://aviaryan.com/letters/get-good-domain"&gt;my newsletter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>career</category>
      <category>advice</category>
    </item>
    <item>
      <title>Immutable requirements if you want a remote job</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Mon, 03 Feb 2020 10:57:28 +0000</pubDate>
      <link>https://dev.to/aviaryan/immutable-requirements-if-you-want-a-remote-job-7bb</link>
      <guid>https://dev.to/aviaryan/immutable-requirements-if-you-want-a-remote-job-7bb</guid>
      <description>&lt;p&gt;I see many people want to do remote jobs. But in my experience, there are some things that you need before you can have a great remote work career.&lt;/p&gt;

&lt;p&gt;Consider it as the smallest definite checklist. &lt;/p&gt;

&lt;p&gt;Note that these might be true for office jobs as well but there, the requirements are relaxed. &lt;/p&gt;

&lt;p&gt;For example - You can do well even if your communication skills are poor. You might get promoted as well. But having bad communication skills will make it impossible to work remotely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Good communication
&lt;/h2&gt;

&lt;p&gt;You need to communicate well. If you can’t speak English (or your team’s language), that’s an issue. &lt;/p&gt;

&lt;p&gt;Remote work features both spoken and written communication. And you need to be decent at both since confusion or lack of clarity can be harmful to your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-Starter
&lt;/h2&gt;

&lt;p&gt;If your team is in different timezones, often you will be at a spot where you don’t know what to do next and your manager will not be online to tell you. &lt;/p&gt;

&lt;p&gt;Or you just came across an unexpected situation and you will have no one to discuss with. In that case, you need to be able to weigh the choices and make the best decision for the team so that you utilize your time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Okay with some timezone overlap
&lt;/h2&gt;

&lt;p&gt;You will need to do some timezone overlap to work remotely if your team is across the globe.&lt;/p&gt;

&lt;p&gt;A 100% overlap isn't required but there will be meetings and scrum calls and you need to be ready for that. &lt;/p&gt;

&lt;p&gt;Your timezone shouldn’t cause problems for the team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quality work
&lt;/h2&gt;

&lt;p&gt;In remote work, mentorship is scarce. Or not the same as you would get in an office job. So you need to be able to deliver good work.&lt;/p&gt;

&lt;p&gt;Work that gets accepted in the first shot or doesn’t need much to-and-fro. Because, to-and-fro wastes even more time in a remote setting where members live in different, sometimes opposite timezones.&lt;/p&gt;

&lt;p&gt;Also, failing reflects badly in remote work. This is because, in an office job, your manager can see that you did the work or at least tried. But in a remote job, it can be assumed that you didn’t do the work or slacked off.&lt;/p&gt;



&lt;p&gt;If you identify yourself with each of the points mentioned above, consider yourself ready for remote work.&lt;/p&gt;

&lt;p&gt;If not, work on them.&lt;/p&gt;



&lt;p&gt;PS - I am working on a remote jobs list for India. It has &lt;strong&gt;300+ tech remote jobs&lt;/strong&gt; available in the Indian timezone. Check it out. &lt;a href="https://goremote.in/"&gt;GoRemote&lt;/a&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;This article was first posted to my &lt;a href="https://aviaryan.com/letters/requirements-for-remote-job"&gt;newsletter&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>remote</category>
      <category>remotejobs</category>
    </item>
    <item>
      <title>A guide to stale-while-revalidate data fetching with React Hooks</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Mon, 03 Feb 2020 10:54:44 +0000</pubDate>
      <link>https://dev.to/aviaryan/a-guide-to-stale-while-revalidate-data-fetching-with-react-hooks-15do</link>
      <guid>https://dev.to/aviaryan/a-guide-to-stale-while-revalidate-data-fetching-with-react-hooks-15do</guid>
      <description>&lt;p&gt;Leveraging the &lt;a href="https://web.dev/stale-while-revalidate/"&gt;stale-while-revalidate&lt;/a&gt; HTTP &lt;code&gt;Cache-Control&lt;/code&gt; extension is a popular technique. It involves using cached (stale) assets if they are found in the cache, and then revalidating the cache and updating it with a newer version of the asset if needed. Hence the name &lt;code&gt;stale-while-revalidate&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How stale-while-revalidate Works
&lt;/h2&gt;

&lt;p&gt;When a request is sent for the first time, it's cached by the browser. Then, when the same request is sent a second time, the cache is checked first. If the cache of that request is available and valid, the cache is returned as the response. Then, the cache is checked for staleness and is updated if found stale. The &lt;a href="https://web.dev/stale-while-revalidate/#live-example"&gt;staleness of a cache&lt;/a&gt; is determined by the &lt;code&gt;max-age&lt;/code&gt; value present in the &lt;code&gt;Cache-Control&lt;/code&gt; header along with &lt;code&gt;stale-while-revalidate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vlYU1I4W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/s-w-r%2520cc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vlYU1I4W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/s-w-r%2520cc.png" alt="A flowchart tracking stale-while-revalidate logic. It starts with a request. If it's not cached, or if the cache is invalid, the request is sent, the response is returned, and the cache is updated. Otherwise, the cached response is returned, after which the cache is checked for staleness. If it's stale, a request is sent and the cache is updated."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows for &lt;a href="https://www.toptal.com/react/optimizing-react-performance"&gt;fast page loads&lt;/a&gt;, as cached assets are no longer in the critical path. They are loaded instantly. Also, since developers control how often the cache is used and updated, they can prevent browsers from showing overly outdated data to users.&lt;/p&gt;

&lt;p&gt;Readers might be thinking that, if they can have the server use certain headers in its responses and let the browser take it from there, then what's the need of using &lt;a href="https://www.toptal.com/react"&gt;React&lt;/a&gt; and Hooks for caching?&lt;/p&gt;

&lt;p&gt;It turns out the server-and-browser approach only works well when we want to cache static content. What about using &lt;code&gt;stale-while-revalidate&lt;/code&gt; for a dynamic API? It's hard to come up with good values for &lt;code&gt;max-age&lt;/code&gt; and &lt;code&gt;stale-while-revalidate&lt;/code&gt; in that case. Often, invalidating the cache and fetching a fresh response every time a request is sent will be the best option. This effectively means no caching at all. But with React and &lt;a href="https://www.toptal.com/react/react-tutorial-pt2"&gt;Hooks&lt;/a&gt;, we can do better.&lt;/p&gt;

&lt;h2&gt;
  
  
  stale-while-revalidate for the API
&lt;/h2&gt;

&lt;p&gt;We noticed that HTTP's &lt;code&gt;stale-while-revalidate&lt;/code&gt; doesn't work well with dynamic requests like API calls.&lt;/p&gt;

&lt;p&gt;Even if we do end up using it, the browser will return either the cache or the fresh response, not both. This doesn't go well with an API request since we would like fresh responses every time a request is sent. However, waiting for fresh responses delays meaningful usability of the app.&lt;/p&gt;

&lt;p&gt;So what do we do?&lt;/p&gt;

&lt;p&gt;We implement a custom caching mechanism. Within that, we figure out a way to return both the cache and the fresh response. In the UI, the cached response is replaced with a fresh response when it's available. This is how the logic would look:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When a request is sent to the API server endpoint for the first time, cache the response and then return it.&lt;/li&gt;
&lt;li&gt;The next time that same API request happens, use the cached response immediately.&lt;/li&gt;
&lt;li&gt;Then, send the request asynchronously to fetch a new response. When the response arrives, asynchronously propagate changes to the UI and update the cache.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach allows for instantaneous UI updates---because every API request is cached---but also eventual correctness in the UI since fresh response data is displayed as soon as it's available.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will see a step-by-step approach on how to implement this. We will call this approach &lt;strong&gt;stale-while-refresh&lt;/strong&gt; since the UI is actually &lt;em&gt;refreshed&lt;/em&gt; when it gets the fresh response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparations: The API
&lt;/h2&gt;

&lt;p&gt;To kickstart this tutorial, we will first need an API where we fetch data from. Luckily, there are a ton of mock API services available. For this tutorial, we will be using &lt;a href="https://reqres.in"&gt;reqres.in&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The data we fetch is a list of users with a &lt;code&gt;page&lt;/code&gt; query parameter. This is how the fetching code looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://reqres.in/api/users?page=2&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="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&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;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="nx"&gt;json&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;Running this code gives us the following output. Here is a non-repetitive version of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;per_page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;total_pages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;data&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;michael.lawson@reqres.in&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Michael&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Lawson&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://s3.amazonaws.com/uifaces/faces/twitter/follettkyle/128.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// 5 more items&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;You can see that this is like a real API. We have pagination in the response. The &lt;code&gt;page&lt;/code&gt; query parameter is responsible for changing the page, and we have a total of two pages in the dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the API in a React App
&lt;/h2&gt;

&lt;p&gt;Let's see how we use the API in a React App. Once we know how to do it, we will figure out the caching part. We will be using a class to create our component. Here is the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&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="nx"&gt;PropTypes&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;prop-types&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;class&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;users&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;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://reqres.in/api/users?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;componentDidUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&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;render&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;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&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;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;p&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
          &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&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="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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&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;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;propTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isRequired&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that we are getting the &lt;code&gt;page&lt;/code&gt; value via &lt;code&gt;props&lt;/code&gt;, as it often happens in real-world applications. Also, we have a &lt;code&gt;componentDidUpdate&lt;/code&gt; function, which refetches the API data every time &lt;code&gt;this.props.page&lt;/code&gt; changes.&lt;/p&gt;

&lt;p&gt;At this point, it shows a list of six users because the API returns six items per page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kiwfHl7O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/users-list-plain.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kiwfHl7O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/users-list-plain.png" alt="A preview of our React component prototype: six centered lines, each with a photo to the left of a name."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Stale-while-refresh Caching
&lt;/h2&gt;

&lt;p&gt;If we want to add stale-while-refresh caching to this, we need to update our app logic to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cache a request's response uniquely after it is fetched for the first time.&lt;/li&gt;
&lt;li&gt;Return the cached response instantly if a request's cache is found. Then, send the request and return the fresh response asynchronously. Also, cache this response for the next time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can do this by having a global &lt;code&gt;CACHE&lt;/code&gt; object that stores the cache uniquely. For uniqueness, we can use &lt;code&gt;this.props.page&lt;/code&gt; value as a key in our &lt;code&gt;CACHE&lt;/code&gt; object. Then, we simply code the algorithm mentioned above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;apiFetch&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;./apiFetch&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;CACHE&lt;/span&gt; &lt;span class="o"&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;class&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;users&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;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&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;apiFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://reqres.in/api/users?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;json&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;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;span class="nx"&gt;componentDidUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&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;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// same render code as above&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;Since the cache is returned as soon as it is found and since the new response data is returned by &lt;code&gt;setState&lt;/code&gt; as well, this means we have seamless UI updates and no more waiting time on the app from the second request onward. This is perfect, and it is the stale-while-refresh method in a nutshell.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DF-594y2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/swr%2520react.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DF-594y2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/swr%2520react.png" alt="A flowchart tracking the stale-while-refresh logic. It starts with a request. If it's cached, setState() is called with the cached response. Either way, the request is sent, the cache is set, and setState() is called with a fresh response."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;apiFetch&lt;/code&gt; function here is nothing but a wrapper over &lt;code&gt;fetch&lt;/code&gt; so that we can see the advantage of caching in real time. It does this by adding a random user to the list of &lt;code&gt;users&lt;/code&gt; returned by the API request. It also adds a random delay to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;apiFetch&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;300&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;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&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;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getFakeUser&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;json&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&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="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&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;The &lt;code&gt;getFakeUser()&lt;/code&gt; function here is responsible for creating a fake user object.&lt;/p&gt;

&lt;p&gt;With these changes, our API is more real than before.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It has a random delay in responding.&lt;/li&gt;
&lt;li&gt;It returns slightly different data for the same requests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Given this, when we change the &lt;code&gt;page&lt;/code&gt; prop passed to the &lt;code&gt;Component&lt;/code&gt; from our main component, we can see the API caching in action. Try clicking the &lt;strong&gt;Toggle&lt;/strong&gt; button once every few seconds in &lt;a href="https://codesandbox.io/s/fetching-class-comp-swr-56mtl"&gt;this CodeSandbox&lt;/a&gt; and you should see behavior like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZJHpWzKH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/1-class-toggle.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZJHpWzKH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/1-class-toggle.gif" alt="An animation showing the toggling page with caching enabled. The specifics are described in the article."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you look closely, a few things happen.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the app starts and is in its default state, we see a list of seven users. Take note of the last user on the list since it is the user that will be randomly modified the next time this request is sent.&lt;/li&gt;
&lt;li&gt;When we click on Toggle for the first time, it waits for a small amount of time (400-700ms) and then updates the list to the next page.&lt;/li&gt;
&lt;li&gt;Now, we are on the second page. Again take note of the last user in the list.&lt;/li&gt;
&lt;li&gt;Now, we click on Toggle again, and the app will go back to the first page. Notice that now the last entry is still the same user we noted down in Step 1, and then it later changes to the new (random) user. This is because, initially, the cache was being shown, and then the actual response kicked in.&lt;/li&gt;
&lt;li&gt;We click on Toggle again. The same phenomenon happens. The cached response from last time is loaded instantly, and then new data is fetched, and so we see the last entry update from what we noted down in Step 3.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is it, the stale-while-refresh caching we were looking for. But this approach suffers from a code duplication issue. Let's see how it goes if we have another data-fetching component with caching. This component shows the items differently from our first component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Stale-while-refresh to Another Component
&lt;/h2&gt;

&lt;p&gt;We can do this by simply copying the logic from the first component. Our second component shows a list of cats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;CACHE&lt;/span&gt; &lt;span class="o"&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;class&lt;/span&gt; &lt;span class="nx"&gt;Component2&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;cats&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;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&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;apiFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://reqres.in/api/cats?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;json&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;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;span class="nx"&gt;componentDidUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;load&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;render&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;cats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cats&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;cat&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;p&lt;/span&gt;
        &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
          &lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;240&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;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;born&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&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="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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cats&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&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;As you can see, the component logic involved here is pretty much the same as the first component. The only difference is in the requested endpoint and that it shows the list items differently.&lt;/p&gt;

&lt;p&gt;Now, we show both these components side by side. You can see &lt;a href="https://codesandbox.io/s/fetching-2-class-comp-swr-oozzz"&gt;they behave similarly&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1BlnZEnI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/2-class-toggle.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1BlnZEnI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/2-class-toggle.gif" alt="An animation showing toggling with two side-by-side components."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To achieve this result, we had to do a lot of code duplication. If we had multiple components like this, we would be duplicating too much code.&lt;/p&gt;

&lt;p&gt;To solve it in a non-duplicating manner, we can have a Higher-order Component for fetching and caching data and passing it down as props. It's not ideal but it will work. But if we had to do multiple requests in a single component, having multiple Higher-order Components would get ugly really quickly.&lt;/p&gt;

&lt;p&gt;Then, we have the render props pattern, which is probably the best way to do this in class components. It works perfectly, but then again, it is prone to "wrapper hell" and requires us to bind the current context at times. This is not a great developer experience and can lead to frustration and bugs.&lt;/p&gt;

&lt;p&gt;This is where React Hooks save the day. They allow us to box component logic in a reusable container so that we can use it at multiple places. &lt;a href="https://reactjs.org/docs/hooks-intro.html"&gt;React Hooks&lt;/a&gt; were introduced in React 16.8 and they only work with function components. Before we get to React cache control, let's first see how we do simple data fetching in function components.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Data Fetching in Function Components
&lt;/h2&gt;

&lt;p&gt;To fetch API data in function components, we use &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; hooks.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useState&lt;/code&gt; is analogous to class components' &lt;code&gt;state&lt;/code&gt; and &lt;code&gt;setState&lt;/code&gt;. We use this hook to have atomic containers of state inside a function component.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; is a lifecycle hook, and you can think of it as a &lt;a href="https://reactjs.org/docs/hooks-effect.html"&gt;combination&lt;/a&gt; of &lt;code&gt;componentDidMount&lt;/code&gt;, &lt;code&gt;componentDidUpdate&lt;/code&gt;, and &lt;code&gt;componentWillUnmount&lt;/code&gt;. The second parameter passed to &lt;code&gt;useEffect&lt;/code&gt; is called a dependency array. When the dependency array changes, the callback passed as the first argument to &lt;code&gt;useEffect&lt;/code&gt; is run again.&lt;/p&gt;

&lt;p&gt;Here is how we will use these hooks to implement data fetching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&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;useEffect&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;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;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;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;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="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://reqres.in/api/users?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&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;setUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;span class="nx"&gt;page&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;usersDOM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&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;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;p&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
        &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&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="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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;usersDOM&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By specifying &lt;code&gt;page&lt;/code&gt; as a dependency to &lt;code&gt;useEffect&lt;/code&gt;, we instruct React to run our useEffect callback every time &lt;code&gt;page&lt;/code&gt; is changed. This is just like &lt;code&gt;componentDidUpdate&lt;/code&gt;. Also, &lt;code&gt;useEffect&lt;/code&gt; always runs the first time so it works like &lt;code&gt;componentDidMount&lt;/code&gt; too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stale-while-refresh in Function Components
&lt;/h2&gt;

&lt;p&gt;We know that &lt;code&gt;useEffect&lt;/code&gt; is similar to component lifecycle methods. So we can modify the callback function passed to it to create the stale-while-refresh caching we had in class components. Everything remains the same except the &lt;code&gt;useEffect&lt;/code&gt; hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;CACHE&lt;/span&gt; &lt;span class="o"&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;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;apiFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://reqres.in/api/users?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&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;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// ... create usersDOM from users&lt;/span&gt;

  &lt;span class="k"&gt;return&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;usersDOM&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Thus, we have stale-while-refresh caching working in a function component.&lt;/p&gt;

&lt;p&gt;We can do the same for the second component, that is, convert it to function and implement stale-while-refresh caching. &lt;a href="https://codesandbox.io/s/fetching-2-func-comp-swr-bekhg"&gt;The result&lt;/a&gt; will be identical to what we had in classes.&lt;/p&gt;

&lt;p&gt;But that's not any better than class components, is it? So let's see how we can use the power of a custom hook to create modular stale-while-refresh logic that we can use across multiple components.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Custom Stale-while-refresh Hook
&lt;/h2&gt;

&lt;p&gt;First, let's narrow down the logic we want to move into a custom hook. If you look at the previous code, you know it's the &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; part. More specifically, this is the logic we want to modularize.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;apiFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://reqres.in/api/users?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&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;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;setUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since we have to make it generic, we will have to make the URL dynamic. So we need to have &lt;code&gt;url&lt;/code&gt; as an argument. We will need to update the caching logic, too, since multiple requests can have the same &lt;code&gt;page&lt;/code&gt; value. Luckily, when &lt;code&gt;page&lt;/code&gt; is included with the endpoint URL, it yields a unique value for every unique request. So we can just use the entire URL as a key for caching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;apiFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&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;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's pretty much it. After wrapping it inside a function, we will have our custom hook. Have a look below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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;CACHE&lt;/span&gt; &lt;span class="o"&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;useStaleRefresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&lt;/span&gt; &lt;span class="o"&gt;=&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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;defaultValue&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;// cacheID is how a cache is identified against a unique request&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// look in cache and set response if present&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cacheID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cacheID&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// fetch new data&lt;/span&gt;
    &lt;span class="nx"&gt;apiFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newData&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;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cacheID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;span class="nx"&gt;url&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;data&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;Notice we have added another argument called &lt;code&gt;defaultValue&lt;/code&gt; to it. The default value of an API call can be different if you use this hook in multiple components. That's why we have made it customizable.&lt;/p&gt;

&lt;p&gt;The same can be done for the &lt;code&gt;data&lt;/code&gt; key in the &lt;code&gt;newData&lt;/code&gt; object. If your custom hook returns a variety of data, you might want to just return &lt;code&gt;newData&lt;/code&gt; and not &lt;code&gt;newData.data&lt;/code&gt; and handle that traversal on the component side.&lt;/p&gt;

&lt;p&gt;Now that we have our custom hook, which does the heavy lifting of stale-while-refresh caching, here is how we plug it into our components. Notice the sheer amount of code we were able to reduce. Our entire component is now just three statements. That's a big win.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useStaleRefresh&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;./useStaleRefresh&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;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useStaleRefresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://reqres.in/api/users?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&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;usersDOM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&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;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;p&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
        &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&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="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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;usersDOM&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can do the same for the second component. It will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&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;Component2&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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;cats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useStaleRefresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://reqres.in/api/cats?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="c1"&gt;// ... create catsDOM from cats&lt;/span&gt;

  &lt;span class="k"&gt;return&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;catsDOM&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's easy to see how much boilerplate code we can save if we use this hook. The code looks better as well. If you want to see the entire app in action, head over to &lt;a href="https://codesandbox.io/s/2-func-swr-custom-hook-lstq9"&gt;this CodeSandbox&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a Loading Indicator to useStaleRefresh
&lt;/h2&gt;

&lt;p&gt;Now that we have the basics on point, we can add more features to our custom hook. For example, we can add an &lt;code&gt;isLoading&lt;/code&gt; value in the hook that is true whenever a unique request is sent and we don't have any cache to show in the meanwhile.&lt;/p&gt;

&lt;p&gt;We do this by having a separate state for &lt;code&gt;isLoading&lt;/code&gt; and setting it according to the state of the hook. That is, when no cached web content is available, we set it to &lt;code&gt;true&lt;/code&gt;, otherwise we set it to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is the updated hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&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;useStaleRefresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&lt;/span&gt; &lt;span class="o"&gt;=&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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;defaultValue&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;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&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="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;// cacheID is how a cache is identified against a unique request&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// look in cache and set response if present&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cacheID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cacheID&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="nx"&gt;setLoading&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// else make sure loading set to true&lt;/span&gt;
      &lt;span class="nx"&gt;setLoading&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="c1"&gt;// fetch new data&lt;/span&gt;
    &lt;span class="nx"&gt;apiFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newData&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;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cacheID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;setLoading&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="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;url&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&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;We can now use the new &lt;code&gt;isLoading&lt;/code&gt; value in our components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&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;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useStaleRefresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://reqres.in/api/users?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&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="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;Loading&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ... create usersDOM from users&lt;/span&gt;

  &lt;span class="k"&gt;return&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;usersDOM&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that &lt;a href="https://codesandbox.io/s/2-func-swr-custom-hook-loading-gd0bs"&gt;with that done&lt;/a&gt;, you see "Loading" text when a unique request is sent for the first time and no cache is present.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qyUL521Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/loading-2-list.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qyUL521Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://s3.amazonaws.com/aviaryan/blog/swr-react/loading-2-list.gif" alt="An animation showing the component with a loading indicator implemented."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Making useStaleRefresh Support Any async Function
&lt;/h2&gt;

&lt;p&gt;We can make our custom hook even more powerful by making it support any &lt;code&gt;async&lt;/code&gt; function rather than just &lt;code&gt;GET&lt;/code&gt; network requests. The basic idea behind it will remain the same.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the hook, you call an async function that returns a value after some time.&lt;/li&gt;
&lt;li&gt;Each unique call to an async function is properly cached.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A simple concatenation of &lt;code&gt;function.name&lt;/code&gt; and &lt;code&gt;arguments&lt;/code&gt; will work as a cache key for our use case. Using that, this is how our hook will look:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&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;useState&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="nx"&gt;useRef&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;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="nx"&gt;isEqual&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;lodash/isEqual&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;CACHE&lt;/span&gt; &lt;span class="o"&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;useStaleRefresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&lt;/span&gt; &lt;span class="o"&gt;=&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;prevArgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;defaultValue&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;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&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="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;// args is an object so deep compare to rule out false changes&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prevArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&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;}&lt;/span&gt;
    &lt;span class="c1"&gt;// cacheID is how a cache is identified against a unique request&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hashArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// look in cache and set response if present&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cacheID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cacheID&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="nx"&gt;setLoading&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// else make sure loading set to true&lt;/span&gt;
      &lt;span class="nx"&gt;setLoading&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="c1"&gt;// fetch new data&lt;/span&gt;
    &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newData&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;CACHE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cacheID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;setLoading&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="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;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fn&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="nx"&gt;prevArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;args&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;hashArgs&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&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="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arg&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;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&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;acc&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&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;As you can see, we are using a combination of function name and its stringified arguments to uniquely identify a function call and thus cache it. This works for our simple app, but this algorithm is prone to collisions and slow comparisons. (With unserializable arguments, it won't work at all.) So for real-world apps, a proper hashing algorithm is more appropriate.&lt;/p&gt;

&lt;p&gt;Another thing to note here is the use of &lt;a href="https://reactjs.org/docs/hooks-reference.html#useref"&gt;&lt;code&gt;useRef&lt;/code&gt;&lt;/a&gt;. &lt;code&gt;useRef&lt;/code&gt; is used to persist data through the entire lifecycle of the enclosing component. Since &lt;code&gt;args&lt;/code&gt; is an array---which is an object in JavaScript---every re-render of the component using the hook causes the &lt;code&gt;args&lt;/code&gt; reference pointer to change. But &lt;code&gt;args&lt;/code&gt; is part of the dependency list in our first &lt;code&gt;useEffect&lt;/code&gt;. So &lt;code&gt;args&lt;/code&gt; changing can make our &lt;code&gt;useEffect&lt;/code&gt; run even when nothing changed. To counter that, we do a deep-comparison between old and current &lt;code&gt;args&lt;/code&gt; using &lt;a href="https://lodash.com/docs/4.17.15#isEqual"&gt;isEqual&lt;/a&gt; and only let the &lt;code&gt;useEffect&lt;/code&gt; callback run if &lt;code&gt;args&lt;/code&gt; actually changed.&lt;/p&gt;

&lt;p&gt;Now, we can use this new &lt;code&gt;useStaleRefresh&lt;/code&gt; hook as follows. Notice the change in &lt;code&gt;defaultValue&lt;/code&gt; here. Since it's a general-purpose hook, we are not relying on our hook to return the &lt;code&gt;data&lt;/code&gt; key in the response object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&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;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&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;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useStaleRefresh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;apiFetch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`https://reqres.in/api/users?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&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;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&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="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;Loading&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&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;usersDOM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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;p&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;
        &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&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="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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;usersDOM&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can find the entire code in &lt;a href="https://codesandbox.io/s/swr-custom-hook-loading-async-z56zd"&gt;this CodeSandbox&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;The &lt;code&gt;useStaleRefresh&lt;/code&gt; hook we created in this article is a proof of concept that shows what's possible with React Hooks. Try to play with the code and see if you can fit it into your application.&lt;/p&gt;

&lt;p&gt;Alternatively, you can also try leveraging &lt;code&gt;stale-while-revalidate&lt;/code&gt; via a popular, well-maintained open-source library like &lt;a href="https://github.com/zeit/swr"&gt;swr&lt;/a&gt; or &lt;a href="https://github.com/tannerlinsley/react-query"&gt;react-query&lt;/a&gt;. Both are powerful &lt;a href="https://www.toptal.com/react/navigating-the-react-ecosystem"&gt;libraries&lt;/a&gt; and support a host of features that help with API requests.&lt;/p&gt;

&lt;p&gt;React Hooks are a game-changer. They allow us to share component logic elegantly. This was not possible before because the component state, lifecycle methods, and rendering were all packaged into one entity: class components. Now, we can have different modules for all of them. This is great for composability and writing better code. I am using function components and hooks for all the new React code I write, and I highly recommend this to all React developers.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;This article was first posted on &lt;a href="https://www.toptal.com/react-hooks/stale-while-revalidate"&gt;Toptal's Engineering Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>react</category>
      <category>hooks</category>
    </item>
    <item>
      <title>How to get guidance and mentorship as a Computer Science college fresher</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Wed, 01 Jan 2020 10:32:00 +0000</pubDate>
      <link>https://dev.to/aviaryan/how-to-get-guidance-and-mentorship-as-a-computer-science-college-fresher-5c94</link>
      <guid>https://dev.to/aviaryan/how-to-get-guidance-and-mentorship-as-a-computer-science-college-fresher-5c94</guid>
      <description>&lt;p&gt;I get some requests from students asking for guidance and mentorship. But I don’t have the time. So I am writing a post which will be more valuable than any mentorship I can give, provided you follow it.&lt;/p&gt;

&lt;p&gt;It involves learning using &lt;strong&gt;free&lt;/strong&gt; online resources. So there’s no reason why you can’t do this. We will be using only three websites for our learning needs.&lt;/p&gt;

&lt;p&gt;Let’s go!&lt;/p&gt;

&lt;h2&gt;
  
  
  0. Learn a programming language
&lt;/h2&gt;

&lt;p&gt;You will need to learn a programming language to kickstart your Computer Science journey. Don’t worry about getting good at it yet. Knowing the basics will do. I would &lt;a href="https://www.youtube.com/watch?v=KJgsSFOSQv0"&gt;recommend C&lt;/a&gt;. But you can &lt;a href="https://www.youtube.com/watch?v=rfscVS0vtbw"&gt;start with Python&lt;/a&gt; if you find it overwhelming. At this point, the programming language you choose doesn’t matter. &lt;strong&gt;So just get started with anything&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. HackerRank
&lt;/h2&gt;

&lt;p&gt;As a Computer Science graduate, you need a basic understanding of algorithms and data structures. &lt;a href="https://www.hackerrank.com/"&gt;HackerRank&lt;/a&gt; has a beginner-friendly interface and it’s a great place to learn and practice them. We will concentrate on only 3 sections on the website.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.hackerrank.com/domains/algorithms"&gt;Algorithms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.hackerrank.com/domains/data-structures"&gt;Data Structures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.hackerrank.com/domains/mathematics"&gt;Mathematics&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Solving 150 problems from the above sections (combined) gives you a good base. 50 from each. That’s your target.&lt;/p&gt;

&lt;p&gt;If you don’t understand something, google it. Then google it (drill-down) more. People have written articles and made videos on everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. FreeCodeCamp
&lt;/h2&gt;

&lt;p&gt;Once you have some algorithm foundations, we can move into software development. &lt;a href="https://www.freecodecamp.org/learn/"&gt;FreeCodeCamp&lt;/a&gt; is a great start to this. It has an extensive tutorial for learning how to make websites and web-apps from scratch. You can go through its &lt;a href="https://www.freecodecamp.org/learn/"&gt;curriculum&lt;/a&gt;. Complete it.&lt;/p&gt;

&lt;p&gt;Also join their &lt;a href="https://www.freecodecamp.org/forum"&gt;forum&lt;/a&gt; so that you can discuss with other learners, ask questions and help others.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Coursera
&lt;/h2&gt;

&lt;p&gt;After you have a working knowledge of algorithms and making web-apps, you can go to &lt;a href="https://www.coursera.org/"&gt;Coursera&lt;/a&gt;. It has free courses on everything. The ‘free’ part is not straight-forward so please &lt;a href="https://clearlydecoded.com/you-can-still-take-coursera-courses-for-free"&gt;refer to this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://www.coursera.org/"&gt;Coursera&lt;/a&gt;, &lt;a href="https://www.coursera.org/search?query=programming"&gt;search&lt;/a&gt; for what you want to learn, and then learn it. &lt;/p&gt;

&lt;p&gt;If you are not sure what to learn, the &lt;a href="https://www.coursera.org/browse/computer-science"&gt;Computer Science&lt;/a&gt; section can give you some ideas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pick any course you want and go with it&lt;/strong&gt;. All courses are of high-quality. The rating for the course shows that.&lt;/p&gt;

&lt;p&gt;Example - Here are the specializations (i.e. a collection of courses) to learn &lt;a href="https://www.coursera.org/specializations/android-app-development"&gt;Android Development&lt;/a&gt;, &lt;a href="https://www.coursera.org/specializations/game-development#courses"&gt;Game Development&lt;/a&gt; and &lt;a href="https://www.coursera.org/specializations/python"&gt;Python&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Search for anything and you will find it. Then learn it, if you want. Keep doing this over and over.&lt;/p&gt;

&lt;p&gt;If for some reason, you can’t get a course for free, apply for their financial aid. You will get accepted. They are very gracious towards students.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I know if I am on the right path and learning the right thing?
&lt;/h2&gt;

&lt;p&gt;Don’t worry about learning the right thing. Learn anything that interests you and sounds right. Learning things on your own will make you a better learner. This will help you pick up anything in the future. And that trait alone is all you need to have a great career in tech. So in short, just keep learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;After you have been through a few courses and are comfortable writing code and making things, you should participate in &lt;a href="https://summerofcode.withgoogle.com/"&gt;Google Summer of Code&lt;/a&gt;. I have a &lt;a href="https://aviaryan.com/letters/gsoc-is-easy"&gt;step-by-step guide&lt;/a&gt; for it as well.&lt;/p&gt;

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

&lt;p&gt;If you follow all the steps above, you will reach a point where you will be able to &lt;strong&gt;self-mentor&lt;/strong&gt; yourself. You will know what things to learn and what to avoid. When to contact someone for a query and when to google it yourself. It’s important to get this feeling for yourself because tech is ever-changing. That’s why I am not a fan of step-by-step mentorships in tech. &lt;/p&gt;

&lt;p&gt;Explore the wild, develop your senses, and keep going. You will soon reach a good place in your career.&lt;/p&gt;

&lt;p&gt;Best of luck!&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;First posted on &lt;a href="https://aviaryan.com/blog/self-mentorship-cs"&gt;my blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>students</category>
      <category>fresher</category>
      <category>career</category>
      <category>college</category>
    </item>
    <item>
      <title>Some helpful Bash scripts I use daily</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Wed, 25 Dec 2019 13:00:10 +0000</pubDate>
      <link>https://dev.to/aviaryan/some-helpful-bash-scripts-i-use-daily-40bd</link>
      <guid>https://dev.to/aviaryan/some-helpful-bash-scripts-i-use-daily-40bd</guid>
      <description>&lt;p&gt;I posted a tweet about how investing time learning Bash scripting and various command-line tools is always worth it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/aviaryan123/status/1194474985013891072"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_PFqYQJg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/email/bash-scripts/bash-tweet.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every time I learn a command-line tool, I am like how did I work without this. Command-line tools are awesome. In this email, I will talk about a few bash scripts or aliases I use regularly. You should find a few of them useful in your digital life.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preventing system sleep in Mac
&lt;/h2&gt;

&lt;p&gt;System sleep in Mac can be a huge problem if you have an ongoing task like a large download as it stops the task. So I use this alias to prevent my Mac from sleeping.&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;alias &lt;/span&gt;&lt;span class="nv"&gt;nosleep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;caffeinate &lt;span class="nt"&gt;-t&lt;/span&gt; 360000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I place this in my &lt;code&gt;.bashrc&lt;/code&gt; file. The parameter 360000 is seconds to keep awake so this command keeps my Mac awake for 100 hours, enough time to finish that download.&lt;/p&gt;
&lt;h2&gt;
  
  
  Counting lines of code in a project
&lt;/h2&gt;

&lt;p&gt;While working on some large projects, I like to keep track of how much work has been done. This one-liner helps to do so.&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;alias &lt;/span&gt;&lt;span class="nv"&gt;sloc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git ls-files &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;*.js*&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;*.scss&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; | xargs wc -l"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is currently set to include &lt;code&gt;js&lt;/code&gt;, &lt;code&gt;jsx&lt;/code&gt; , &lt;code&gt;json&lt;/code&gt; and &lt;code&gt;scss&lt;/code&gt; as source code files. Here is how the output looks like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uzUgEi5d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/email/bash-scripts/sloc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uzUgEi5d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/email/bash-scripts/sloc.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  View list of aliases in your source file
&lt;/h2&gt;

&lt;p&gt;If you have lots of aliases in your source file and tend to forget what you named them, this command will help. I keep all my aliases in a file called &lt;code&gt;mymacrc&lt;/code&gt; which is further included in &lt;code&gt;.bashrc&lt;/code&gt; using &lt;code&gt;source ~/mymacrc&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;So if I want to see the list of all aliases, I use this.&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;alias &lt;/span&gt;&lt;span class="nv"&gt;lsalias&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"grep -in --color -e '^alias&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="s2"&gt;+*' ~/mymacrc | sed 's/alias //' | grep --color -e ':[a-z][a-z0-9]*'"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KqZMYpVF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/email/bash-scripts/lsalias.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KqZMYpVF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/email/bash-scripts/lsalias.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Remove Dangling Docker images
&lt;/h2&gt;

&lt;p&gt;Dangling Docker images are temporary images created by Docker to run a container. You can see them by running &lt;code&gt;docker images&lt;/code&gt;. They have no name and are usually copies of their parent image. Although, they still take up disk space and for some reason, aren’t removed by Docker as quickly as they should be.&lt;/p&gt;

&lt;p&gt;To remove them, I have this one-liner.&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;alias &lt;/span&gt;&lt;span class="nv"&gt;dcdangling&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"docker rmi &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;(docker images -f &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;dangling=true&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; -q)"&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Back up key files to Dropbox
&lt;/h2&gt;

&lt;p&gt;Dropbox recently stopped supporting sync within symlinks. If you are like me, you probably used Dropbox just for that. Needless to say, I was disappointed. But then I found another way to sync to Dropbox. By using rsync.&lt;/p&gt;

&lt;p&gt;But rsync doesn’t work with Dropbox directly. There is a wrapper over rsync called &lt;a href="https://rclone.org/"&gt;rclone&lt;/a&gt; that can do this for us.&lt;/p&gt;

&lt;p&gt;Here is the code that syncs a folder in my HOME directory called &lt;code&gt;syncs/osxdropbox&lt;/code&gt; to the Dropbox root folder called &lt;code&gt;osxrsync&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;rclone &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;--exclude&lt;/span&gt; &lt;span class="s2"&gt;".DS_Store"&lt;/span&gt; /Users/aviaryan/syncs/osxdropbox dropbox:osxrsync
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This directory, in turn, contains symlinks to all other folders I want to sync. For example, here is the list of folders I am syncing to Dropbox.&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;v&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/Users/aviaryan"&lt;/span&gt;
&lt;span class="nv"&gt;d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt;/syncs/osxdropbox"&lt;/span&gt;

&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt;/scripts"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$d&lt;/span&gt;&lt;span class="s2"&gt;/scripts"&lt;/span&gt;
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt;/.ssh"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$d&lt;/span&gt;&lt;span class="s2"&gt;/.ssh"&lt;/span&gt;
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt;/Documents"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$d&lt;/span&gt;&lt;span class="s2"&gt;/Documents"&lt;/span&gt;
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt;/AlfredSettings"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$d&lt;/span&gt;&lt;span class="s2"&gt;/AlfredSettings"&lt;/span&gt;
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt;/mymacrc"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$d&lt;/span&gt;&lt;span class="s2"&gt;/mymacrc"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And you can see the same in my Dropbox. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Foc6LTrR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/email/bash-scripts/dropbox-sync-folder.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Foc6LTrR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.amazonaws.com/aviaryan/email/bash-scripts/dropbox-sync-folder.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But running rclone every time is not a good idea. To do it automatically, I use the system’s cron.&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;# edit crontab&lt;/span&gt;
crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;span class="c"&gt;# add a line for our cron job&lt;/span&gt;
0 14 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; rclone &lt;span class="nb"&gt;sync&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;--exclude&lt;/span&gt; &lt;span class="s2"&gt;".DS_Store"&lt;/span&gt; /Users/aviaryan/syncs/osxdropbox dropbox:osxrsync
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The above cron job runs the dropbox backup every day at 2 pm. Since my system is usually switched on at 2 pm, it works great for me.&lt;/p&gt;



&lt;p&gt;EDIT - Forgot that I had a GitHub repo of some actual bash scripts. Check it out. It's a good collection. 😀&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/aviaryan"&gt;
        aviaryan
      &lt;/a&gt; / &lt;a href="https://github.com/aviaryan/utility-bash-scripts"&gt;
        utility-bash-scripts
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🤓 Useful bash scripts to do automatable tasks with a single command
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
🤓 Utility bash scripts&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/aviaryan/utility-bash-scripts/master/.github/CONTRIBUTING.md"&gt;&lt;img src="https://camo.githubusercontent.com/a38874090b7e0830c98045c12effe25c1081198b539ecd40c8eb635e5ce7b7e0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f6e7472696275746f72732d6e65656465642d79656c6c6f772e737667" alt="Contributors needed"&gt;&lt;/a&gt; &lt;a href="https://travis-ci.org/aviaryan/utility-bash-scripts" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/46371da335a9625870fcacfa97fdda8876553a30c37bf1f7b216b88af95318b5/68747470733a2f2f7472617669732d63692e6f72672f617669617279616e2f7574696c6974792d626173682d736372697074732e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Utility bash scripts to do automatable tasks with a single command. We have scripts to download youtube videos, download music from youtube, convert media files, etc.&lt;/p&gt;
&lt;p&gt;Contribute and add your secret script.&lt;/p&gt;
&lt;h2&gt;
📝 NOTES&lt;/h2&gt;
&lt;p&gt;Download scripts download to &lt;code&gt;~/Downloads/&lt;/code&gt; folder. For videos, they download to &lt;code&gt;~/Downloads/Videos&lt;/code&gt; and for audio, they download to &lt;code&gt;~/Downloads/Music&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For best results, clone this git repo to a fixed location on your computer and add it to &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;cd&lt;/span&gt; &lt;span class="pl-k"&gt;~&lt;/span&gt;
git clone https://github.com/aviaryan/utility-bash-scripts.git utility-scripts
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; utility-scripts
&lt;span class="pl-k"&gt;export&lt;/span&gt; PATH=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;$(&lt;/span&gt;pwd&lt;span class="pl-pds"&gt;)&lt;/span&gt;&lt;/span&gt;:&lt;span class="pl-smi"&gt;$PATH&lt;/span&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
📜 SCRIPTS&lt;/h2&gt;
&lt;h3&gt;
🔻 Download video from YouTube in MP4 format&lt;/h3&gt;
&lt;p&gt;Script: &lt;a href="https://raw.githubusercontent.com/aviaryan/utility-bash-scripts/master/youtube-video"&gt;youtube-video&lt;/a&gt;&lt;br&gt;
Dependencies: &lt;a href="https://github.com/rg3/youtube-dl"&gt;youtube-dl&lt;/a&gt;, &lt;a href="https://www.ffmpeg.org/" rel="nofollow"&gt;ffmpeg&lt;/a&gt;, &lt;a href="https://aria2.github.io/" rel="nofollow"&gt;aria2c&lt;/a&gt; (optional)&lt;/p&gt;
&lt;div class="highlight highlight-source-shell js-code-highlight"&gt;
&lt;pre&gt;youtube-video &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;https://www.youtube.com/watch?v=HgfojLtSBTM&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
🔀 Merge video and audio together&lt;/h3&gt;
&lt;p&gt;Script: &lt;a href="https://raw.githubusercontent.com/aviaryan/utility-bash-scripts/master/vamerge"&gt;vamerge&lt;/a&gt;&lt;br&gt;
Dependencies: &lt;a href="https://www.ffmpeg.org/" rel="nofollow"&gt;ffmpeg&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight highlight-source-shell js-code-highlight"&gt;
&lt;pre&gt;vamerge &lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt;path to video file&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-k"&gt;&amp;lt;&lt;/span&gt;path to audio file&lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; the order is important, first video, then audio&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/aviaryan/utility-bash-scripts"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;






&lt;blockquote&gt;
&lt;p&gt;First published in my &lt;a href="https://aviaryan.com/letters/bash-scripts-mine"&gt;newsletter&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>bash</category>
      <category>scripting</category>
      <category>automation</category>
    </item>
    <item>
      <title>I took a break to fight burnout</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Wed, 25 Dec 2019 12:57:34 +0000</pubDate>
      <link>https://dev.to/aviaryan/i-took-a-break-to-fight-burnout-5e1j</link>
      <guid>https://dev.to/aviaryan/i-took-a-break-to-fight-burnout-5e1j</guid>
      <description>&lt;p&gt;Burnout. Chances are, most of you are familiar with it. But for someone new to this career, an introduction is due.&lt;/p&gt;

&lt;p&gt;Burnout is a state of mental, physical and emotional exhaustion. Often you don’t realize when it starts happening. Finding why it is happening is even harder. It is very common in our field of work.&lt;/p&gt;

&lt;p&gt;Our jobs require us to work from a computer, 8 hours a day, 5 days a week. Humans weren’t like this until the last 150 years or so. So a 9-5 office desk schedule is un-natural. But that’s not it.&lt;/p&gt;

&lt;p&gt;Our work can get repetitive over time. This creates boredom and lethargy. It can also get challenging at times, leaving us mentally exhausted after a full day of work. If many such days go by, the mental damage compounds.&lt;/p&gt;

&lt;p&gt;Similarly, our work requires minimum physical movements. This creates a feedback loop of reducing physical movements. Soon we find ourselves not wanting to do large physical movements. This tricks us into thinking we are physically exhausted.&lt;/p&gt;

&lt;p&gt;If you are a remote worker, the lack of human interaction can make you socially inept. Humans are social creatures. Lack of social interactions makes us feel emotionally drained.&lt;/p&gt;

&lt;p&gt;So burnout is inevitable in this career. Learning to recognize it or avoid it altogether is KEY.&lt;/p&gt;

&lt;p&gt;I realized I was getting into a similar situation recently. So I decided to take a 7-day leave. I did no work at that time. This worked wonders. I felt recharged and was looking forward to getting back to work by the 4th day. After coming back, the results spoke for themselves.&lt;/p&gt;

&lt;p&gt;So if you feel similar, take a break. Try a 2-day complete disconnect from work for starters. I am sure it will help you. If it doesn’t, try a longer break.&lt;/p&gt;

&lt;p&gt;There are also ways to reduce burnout on a day to day basis.&lt;/p&gt;

&lt;p&gt;You can join a gym or put something physical into your routine. This will help you act more like humans from 150 years ago, tricking your brain into feeling more okay.&lt;/p&gt;

&lt;p&gt;You can also start a hobby apart from work. A hobby which doesn’t involve computers. Think gardening, cooking, playing music.&lt;/p&gt;

&lt;p&gt;Competing in a sport or activity works even better. Since you are competing, you want to win. You will be 100% attentive when you do that activity. This guarantees that you will disconnect from work, giving you a proper break.&lt;/p&gt;

&lt;p&gt;These are my top tricks to beat burnout. What are you doing to beat this devil?&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;First published in &lt;a href="https://aviaryan.com/letters/fighting-burnout"&gt;my newsletter&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>burnout</category>
      <category>career</category>
    </item>
    <item>
      <title>Should you keep your code dependency-free?</title>
      <dc:creator>Avi Aryan</dc:creator>
      <pubDate>Mon, 25 Nov 2019 03:25:10 +0000</pubDate>
      <link>https://dev.to/aviaryan/should-you-keep-your-code-dependency-free-d7a</link>
      <guid>https://dev.to/aviaryan/should-you-keep-your-code-dependency-free-d7a</guid>
      <description>&lt;p&gt;I posted this tweet on Twitter about a trending JS library 🤷🏻‍♂️ called &lt;a href="https://immerjs.github.io/immer/docs/introduction" rel="noopener noreferrer"&gt;Immer&lt;/a&gt;. Immer is a small library that helps to work with immutable data in JavaScript. &lt;/p&gt;

&lt;p&gt;Its main purpose is helping create immutable objects which are a big pain point in the language. That’s because objects are copied and compared by reference. Hence it’s easy to do something wrong when working with them. Take a look below.&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="nx"&gt;obj1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// { a:2 }&lt;/span&gt;
&lt;span class="nx"&gt;obj2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;obj1&lt;/span&gt;
&lt;span class="c1"&gt;// { a:2 }&lt;/span&gt;
&lt;span class="nx"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;span class="nx"&gt;obj1&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;obj2&lt;/span&gt;
&lt;span class="c1"&gt;// true (but why, didn't I modify obj2?)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the way, here is &lt;a href="https://twitter.com/aviaryan123/status/1192304429237710850" rel="noopener noreferrer"&gt;my tweet&lt;/a&gt;. I was particularly excited about Immer because it helps with deep state updates in React. No more messing around with &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt; and the whole &lt;a href="https://aviaryan.com/blog/intro-functional-js" rel="noopener noreferrer"&gt;functional programming squad&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Immediately &lt;a href="https://twitter.com/sigismundf/status/1192319876922257408" rel="noopener noreferrer"&gt;someone tweeted back&lt;/a&gt; about the problems of using yet another library and how it is similar to the jQuery hell. In jQuery, we have a plugin for every feature you want to add. Think parallax, modal, spinners, and whatnot. If the developer is not careful, the jQuery app soon becomes tangled because of the many non-standardised dependencies. This makes it hard to maintain.&lt;/p&gt;

&lt;p&gt;I partly agree.&lt;/p&gt;

&lt;p&gt;Reducing dependencies which are like out-of-your-control pieces in an application is certainly important. They also bloat the app and increase the maintenance burden. If you are not careful while using them, they can slow it down as well.&lt;/p&gt;

&lt;p&gt;Imagine using a website or an app that takes many seconds to load or takes a lot of time to download. It’s a pain. It drives a fraction of users away and for those that stay, it wastes their time. This should be avoided when possible.&lt;/p&gt;

&lt;p&gt;But not using a helpful dependency can also mean we are creating the solution ourselves. This can result in more time to market and more chances of bugs. Libraries and frameworks like Immer, Bootstrap, React are extensively tested to remove bugs. Creating your own solution means you will have bugs that will crawl out to the end-users.&lt;/p&gt;

&lt;p&gt;Again something we don’t want.&lt;/p&gt;

&lt;p&gt;As a developer, our most important job is to create things that solve problems. It’s very easy to want to use a library or a framework for the sake of it. But we should do so while focusing on the end goal, which is, fulfilling human needs, desires, and fantasies. Anything else is just not of the same value.&lt;/p&gt;

&lt;p&gt;This reminds me of a tweet I &lt;a href="https://twitter.com/thekitze/status/1191748577363726341" rel="noopener noreferrer"&gt;retweeted&lt;/a&gt; recently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/thekitze/status/1191748577363726341" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Faviaryan%2Femail%2Fdependency-free%2Fkitze.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coding and building is also a means to an end. Sure, it can be fun for us (it is for me) but we must not forget why we do it for. If the tool we build is not solving someone’s problem, it is not as impactful as building a tool that solves someone’s problem.&lt;/p&gt;

&lt;p&gt;For that, we should use whatever works. Whatever solves the problem correctly, most efficiently, for the largest number of people.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;This article was first posted on my &lt;a href="https://aviaryan.com/letters/dependency-free" rel="noopener noreferrer"&gt;website&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>opinion</category>
      <category>development</category>
    </item>
  </channel>
</rss>
