<?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: Jack Herrington</title>
    <description>The latest articles on DEV Community by Jack Herrington (@jherr).</description>
    <link>https://dev.to/jherr</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%2F218895%2F5425a184-8a59-4c39-8ee9-682c0c332b26.jpeg</url>
      <title>DEV Community: Jack Herrington</title>
      <link>https://dev.to/jherr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jherr"/>
    <language>en</language>
    <item>
      <title>100% Free Vector Search with OpenLlama, Postgres, NodeJS and NextJS</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Tue, 02 Jul 2024 01:37:40 +0000</pubDate>
      <link>https://dev.to/jherr/100-free-vector-search-with-openllama-postgres-nodejs-and-nextjs-3jm5</link>
      <guid>https://dev.to/jherr/100-free-vector-search-with-openllama-postgres-nodejs-and-nextjs-3jm5</guid>
      <description>&lt;p&gt;So you want to try out vector search but you don’t want to pay &lt;a href="https://openai.com/" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;, or use &lt;a href="https://huggingface.co/" rel="noopener noreferrer"&gt;Huggingface&lt;/a&gt;, and you don’t want to pay a vector database company. I’m here for you. Let’s get vector search going, on your own machine, for free.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfkdskv2ir6r555hg4vo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfkdskv2ir6r555hg4vo.jpg" alt="Abstract Thumbnail Image For This Article"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What Are We Doing?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s take a quick step back and talk about what we are doing and why we are doing it. Vector search of AI embeddings is a way to create a search based on concepts. For example, searching for ‘pet’ might yield results for both dogs and cats. This is super valuable because it means that your customers can get better search results&lt;/p&gt;

&lt;p&gt;To accomplish this we first take the text we want to search and send it to an AI for it to create an “embedding”. An embedding is a lengthy array of floating point values, usually between ~300 and ~1500 numbers.&lt;/p&gt;

&lt;p&gt;The embedding value for cat, dog, and pet would be similar. So if you were to compare cat and dog they would be close, where dog and pizza would not be close.&lt;/p&gt;

&lt;p&gt;What a vector database allows you to do is to store these vectors, along with their associated data (probably the original text of the data). Once the data is stored you can then query the database with a new vector to get any nearby results. For example, if we stored cat and dog with their embeddings in the database, we could then take a input text of “pet”, create the embedding for that, then use that to query the database and we would likely get back cat and dog.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Postgres and OpenLlama?
&lt;/h3&gt;

&lt;p&gt;Postgres is a fantastic database that you can easily install and run locally. And with the pgvector extension to Postgres you can create vector fields that you can then use in your SQL queries.&lt;/p&gt;

&lt;p&gt;There are multiple ways to install Postgres on your machine. On my Mac I used the Postgres.app to install Postgres.&lt;/p&gt;

&lt;p&gt;OpenLlama is a very easy way to install and run AI models locally. I used Homebrew to install OpenLlama using brew install ollama.&lt;/p&gt;

&lt;p&gt;For our simple test application we’ll load all the lines from the &lt;a href="https://www.imdb.com/title/tt0090605/" rel="noopener noreferrer"&gt;1986 horror film Aliens&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Set Up
&lt;/h3&gt;

&lt;p&gt;There are &lt;a href="https://ollama.com/library" rel="noopener noreferrer"&gt;lots of models&lt;/a&gt; to choose from with OpenLlama. For this application I chose &lt;a href="https://ollama.com/library/snowflake-arctic-embed" rel="noopener noreferrer"&gt;snowflake-arctic-embed&lt;/a&gt; because its ideal for fast creation of embeddings. To install it I used the command ollama pull snowflake-arctic-embed .&lt;/p&gt;

&lt;p&gt;The last part of the setup is to create a local Postgres database. You can name it whatever you like, I chose lines because we are searching lines from a movie.&lt;/p&gt;

&lt;p&gt;With the database created we can use the psql command to run some commands. The first is to add the vector extension to the database. That enables the vector field type. To do that I use the create extension command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE EXTENSION vector;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we need to create a table to hold the line text as well as the vectors, here are the commands to create the table along with an index on the position value which is the position of the line in the script.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE lines (
  id bigserial PRIMARY KEY,
  position INT,
  text TEXT,
  embedding VECTOR(1024)
);
CREATE UNIQUE INDEX position_idx ON lines (position);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The important thing to note here is the size of the vector. Different models create different sizes of vector. In the case of our snowflake model the embedding size is 1,024 numbers, so we set the vector size to that.&lt;/p&gt;

&lt;p&gt;You will want to use the same embedding AI for both storage and query. If you use different models then the numbers won’t line up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating The Vector Indexes
&lt;/h3&gt;

&lt;p&gt;As you can imagine, comparing two 1,024 value floating point arrays could be costly. And comparing lots of them could be very costly. So these new vector databases have come up with different indexing models to make that more effecient. The Postgres vector support has different types of indexes, we will use the &lt;a href="https://www.pinecone.io/learn/series/faiss/hnsw/" rel="noopener noreferrer"&gt;Hierarchical Navigable Small Worlds&lt;/a&gt; (HNSW) type to create three different indexes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE INDEX ON lines USING hnsw (embedding vector_ip_ops);
CREATE INDEX ON lines USING hnsw (embedding vector_cosine_ops);
CREATE INDEX ON lines USING hnsw (embedding vector_l1_ops);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Why three? Because there are multiple ways to compare two vectors. There is Cosine, which is often the default, and is good for doing more concept comparison. There is also uclidean, and dot-product comparison. Postgres supports all of these methods (and more).&lt;/p&gt;

&lt;p&gt;Whichever you use you will want to make sure the indexes are enabled for that so that you can get high speed queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Loading The Database
&lt;/h3&gt;

&lt;p&gt;With the model downloaded, and Postgres setup we can now start loading the database with our movie lines and their embeddings. I’ve posted the complete project that also includes a NextJS App Router UI on &lt;a href="https://github.com/jherr/aliens-vector-search" rel="noopener noreferrer"&gt;github&lt;/a&gt;. The &lt;a href="https://github.com/jherr/aliens-vector-search/blob/main/load-embeddings/aliens.script.txt" rel="noopener noreferrer"&gt;script is located in the load-embeddings directory&lt;/a&gt;. The original &lt;a href="https://movietranscript.blogspot.com/2015/11/1986-aliens-english-transcript.html" rel="noopener noreferrer"&gt;data is from this script page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before you can load the data you’ll need to copy the .env.example files to .env and then change the values to match whatever your Postgres connection details.&lt;/p&gt;

&lt;p&gt;To load the embedding into Postgres run node loader.mjs with Node 20 or higher.&lt;/p&gt;

&lt;p&gt;The key parts of the script are the embedding generation:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import ollama from "ollama";
...
  const response = await ollama.embeddings({
    model: "snowflake-arctic-embed",
    prompt: text,
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Where we use the ollama library to invoke the snowflake embedding model with each line of text one-by-one.&lt;/p&gt;

&lt;p&gt;We then insert the line into the database using an INSERT statement:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  await sql`INSERT INTO lines
    (position, text, embedding)
  VALUES
    (${position}, ${text}, ${`[${response.embedding.join(",")}]`})
  `;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The only tricky thing here is how we format the embedding which is by joining all the numbers together into a string and wrapping it in brackets.&lt;/p&gt;

&lt;p&gt;With all the data loaded into the database it’s time we make a query.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making Our First Query
&lt;/h3&gt;

&lt;p&gt;To make sure this works there is a &lt;a href="https://github.com/jherr/aliens-vector-search/blob/main/load-embeddings/test-query.mjs" rel="noopener noreferrer"&gt;test-query.mjs file in the&lt;/a&gt;&lt;a href="https://github.com/jherr/aliens-vector-search/blob/main/load-embeddings/test-query.mjs" rel="noopener noreferrer"&gt;load-embeddings directory&lt;/a&gt;. To make a vector query we first run the model to turn the query into a vector, like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const response = await ollama.embeddings({
  model: "snowflake-arctic-embed",
  prompt: "food",
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this case the prompt is food and we use exactly the same process as we did on the loader script to turn that into an embedding.&lt;/p&gt;

&lt;p&gt;We then use a SQL SELECT statement to query the database with that vector:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const query = await sql`SELECT
  position, text
FROM
  lines
ORDER BY
  embedding &amp;lt;#&amp;gt; ${`[${response.embedding.join(",")}]`} 
LIMIT 10`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We are using ORDER BY to order the records in the database by their similarity to the given embedding then using LIMIT to get back just the top 10 most similar.&lt;/p&gt;

&lt;p&gt;The &amp;lt;#&amp;gt; syntax in the ORDER BY is important because it defines which comparison algorithm to use. From the documentation our options are:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;-&amp;gt; - L2 distance
&amp;lt;#&amp;gt; - (negative) inner product
&amp;lt;=&amp;gt; - cosine distance
&amp;lt;+&amp;gt; - L1 distance (added in 0.7.0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can decide for yourself which comparison provides the best output for your application, but be sure to index the table properly based on that comparison method.&lt;/p&gt;

&lt;p&gt;On my machine this test query yielded, amongst other things:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;317 Guess she don't like the corn bread, either.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Which is a classic line from the movie that indeed references a type of food (corn bread).&lt;/p&gt;

&lt;h3&gt;
  
  
  Putting A User Interface On It
&lt;/h3&gt;

&lt;p&gt;With a little extra effort I put a NextJS App Router interface on it that you can play with by running pnpm dev in the root directory of the project after the database has been loaded and the .env file set up properly.&lt;/p&gt;

&lt;p&gt;This NextJS app uses exactly the same SELECT operation to query the lines from the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;Obviously you’re not going to take an Aliens script searching application production. But from what I’ve shown you here you could search text content, product descriptions, comments, almost any kind of text.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

</description>
      <category>react</category>
      <category>node</category>
      <category>nextjs</category>
      <category>ai</category>
    </item>
    <item>
      <title>NextJS’s Amazing New Streaming Server Actions</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Mon, 04 Dec 2023 23:57:05 +0000</pubDate>
      <link>https://dev.to/jherr/nextjss-amazing-new-streaming-server-actions-3eae</link>
      <guid>https://dev.to/jherr/nextjss-amazing-new-streaming-server-actions-3eae</guid>
      <description>&lt;p&gt;One of the most exciting new advancements in NextJS/React architecture isn’t in NextJS. It’s in Vercel’s AI library. Even there, it’s tucked away in a little corner. It’s the experimental streaming API and what it can do could allow a revolution in application architecture.&lt;/p&gt;

&lt;p&gt;The example in the documentation is a little terse, but the idea is simple. The library provides two key elements: experimental_StreamingReactResponse that allows for API routes or server actions to stream back responses, as well as the useChat hook that invokes the API route or server action and handles the streamed response.&lt;/p&gt;

&lt;p&gt;This streaming functionality is exciting for two reasons. First, streaming used to be limited to just page routes. Now, we can stream data back from server actions and API routes, which can be super handy for longer running transactions.&lt;/p&gt;

&lt;p&gt;However, the second reason is the real mind blower. Here is the server action code from &lt;a href="https://youtu.be/KtTR8Seld98"&gt;my recent video on this topic&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  return new experimental_StreamingReactResponse(stream, {
    ui: async ({ content }) =&amp;gt; {
      const albums = await getSpotifyAlbums(content);
      return (
        &amp;lt;div className="grid grid-cols-2"&amp;gt;
          {albums.map((album) =&amp;gt; (
            &amp;lt;div key={`${album.artist}-${album.name}`} className="p-1"&amp;gt;
              &amp;lt;Album {...album} /&amp;gt;
            &amp;lt;/div&amp;gt;
          ))}
        &amp;lt;/div&amp;gt;
      );
    },
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, we are passing the AI response stream to experimental_StreamingReactResponse which invokes the ui method each time the AI comes back with new content. Within that UI, we can parse that AI response and turn it into any React UI we want. In this case, the div tags are rendered on the server and the Album component is a client component that renders on both the client and the server.&lt;/p&gt;

&lt;p&gt;Think about how we would have had to do this before. The server action or API route would have sent back JSON that the receiving component would have to turn into UI. The more complex the layout and data, the more complex the logic would have to be on the client to manage laying out the components and giving them the right data.&lt;/p&gt;

&lt;p&gt;With this new functionality in the AI library, we can just send back a React Server Component (RSC) stream that the React code on the client can decode back into component instances using the same mechanisms that we use to hydrate the component tree after a page navigation. It’s super slick!&lt;/p&gt;

&lt;p&gt;Unfortunately, all of this awesome component streaming functionality is linked to their AI wrapper, and I don’t know about you but I don’t see those two things as linked. You can stream all kinds of responses, not just from AIs. But hey, this is what we have, and it’s amazing.&lt;/p&gt;

&lt;p&gt;Let’s try it out with a server action. That could be as simple as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use server";
import OpenAI from "openai";
import { OpenAIStream, experimental_StreamingReactResponse, Message } from "ai";

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY!,
});

export async function handler({ messages }: { messages: Message[] }) {
  const response = await openai.chat.completions.create({
    model: "gpt-3.5-turbo",
    stream: true,
    messages: messages.map((m) =&amp;gt; ({
      role: m.role,
      content: m.content,
    })),
  });

  const stream = OpenAIStream(response);

  return new experimental_StreamingReactResponse(stream, {
    ui({ content }) {
      return &amp;lt;div className="italic text-red-800"&amp;gt; {content} &amp;lt;/div&amp;gt;;
    },
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start by importing the AI library from openai as well as the experimental_StreamingReactResponse function that we’ll use to stream the response back to the client.&lt;/p&gt;

&lt;p&gt;Next, we export a function named handler, though you can name it anything you want. The only rule is that it has to be an async function. To use this with the useChat hook, this server action function needs to take an object containing an array of messages as the first argument.&lt;/p&gt;

&lt;p&gt;This async server action function then sends the messages to openai (or whatever AI you want) to start the AI request and to open the stream. For OpenAI, in particular, we need to send the name of the model. There are &lt;a href="https://platform.openai.com/docs/models"&gt;lots to choose from&lt;/a&gt;. We also need to specify that we want a streaming response by setting the stream key to true. Finally, we need to send the list of messages. This list of messages is a set of prompts and responses to and from the AI. And we persist those messages so that the AI has the context of the previous user prompts to apply to the new prompt.&lt;/p&gt;

&lt;p&gt;Once we’ve started the request, we turn that into an OpenAIStream stream from Vercel’s AI library. If you are using a different AI library, you’ll want to use a different stream adapter.&lt;/p&gt;

&lt;p&gt;Finally, we return the experimental_StreamingReactResponse which takes the stream as input and calls the ui function each time a new streamed content message is received. It’s this function that turns that content into a set of tags, React Server Components, and client components, using JSX. In this example, we are simply wrapping the content in a div formatted with Tailwind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Our Server Action
&lt;/h3&gt;

&lt;p&gt;Once we have the server action created, we need to import it into our page. In the example provided by Vercel, we import the handler and then pass it to the Chat component as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { handler } from "./action";
import { Chat } from "./chat";

export const runtime = "edge";

export default function Page() {
  return &amp;lt;Chat handler={handler} /&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Page component is an RSC, and that’s good because only an RSC can import a server action. So, the whole job of this component is to import the handler and send it to the Chat component, which is a client component.&lt;/p&gt;

&lt;p&gt;It’s the Chat client component that is going to talk to the server action handler that the component sends to it. Let’s take it apart in sections.&lt;/p&gt;

&lt;p&gt;In the first part, we import the useChat hook that will drive the interface and we define our Chat component with the handler property that has the server action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use client";
import { useChat } from "ai/react";

export function Chat({ handler }: { handler: any }) {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the Chat client component, we call the useChat hook from the AI library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const { messages, input, handleInputChange, handleSubmit } = useChat({
    api: handler,
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives us some handy data and functions that we can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;messages&lt;/strong&gt;  — This is the array of messages to and from the user and the AI. Each message is an object containing role, content, and ui. Role is a string that tells us whether the message comes from the user or the AI. Content is the text version of the content. And ui has the rendered components from the ui method in the server action.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;input&lt;/strong&gt;  — This is the text string of the input prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;handleInputChange&lt;/strong&gt;  — This is an event handler that you assign to the onChange of the input control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;handleSubmit&lt;/strong&gt;  — This is a form submit function that you assign to the onSubmit of the input form.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We then take that data and the functions and use them in our JSX return.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  return (
    &amp;lt;div className="container mx-auto p-4"&amp;gt;       
      &amp;lt;ul&amp;gt;
        {messages.map((m, index) =&amp;gt; (
          &amp;lt;li key={index}&amp;gt;
             {m.role === "user" ? "User: " : "AI: "} 
            {m.role === "user" ? m.content : m.ui} 
          &amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
      &amp;lt;form
        className="flex gap-2 fixed bottom-0 left-0 w-full p-4 border-t"
        onSubmit={handleSubmit}
      &amp;gt;

        &amp;lt;input
          className="border border-gray-500 rounded p-2 w-full"
          placeholder="what is Next.js…"
          value={input}
          onChange={handleInputChange}
          autoFocus
        /&amp;gt;

        &amp;lt;button type="submit" className="bg-black text-white rounded px-4"&amp;gt;
           Send  
        &amp;lt;/button&amp;gt;

      &amp;lt;/form&amp;gt;

    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above takes the messages and formats them into a simple unordered list. You can, of course, lay this out and style it however you like.&lt;/p&gt;

&lt;p&gt;It’s the ui portion that’s the real magic here. Of course, you can do whatever you want to layout this ui component tree wherever you want it. But the contents of the ui component tree are defined by the server action and that’s the beauty of this whole thing.&lt;/p&gt;

&lt;p&gt;Finally, we need a form and an input to interact with AI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      &amp;lt;form
        className="flex gap-2 fixed bottom-0 left-0 w-full p-4 border-t"
        onSubmit={handleSubmit}
      &amp;gt;

        &amp;lt;input
          className="border border-gray-500 rounded p-2 w-full"
          placeholder="what is Next.js…"
          value={input}
          onChange={handleInputChange}
          autoFocus
        /&amp;gt;

        &amp;lt;button type="submit" className="bg-black text-white rounded px-4"&amp;gt;
           Send  
        &amp;lt;/button&amp;gt;

      &amp;lt;/form&amp;gt;

    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The way the hook is set up, the handleSubmit function needs to be on a form tag, so we wrap our text input in a form tag and put the handleSubmit on the onSubmit.&lt;/p&gt;

&lt;p&gt;Within the form we have the input tag that we connect with the input text by setting the value to input and the onChange to handleInputChange.&lt;/p&gt;

&lt;p&gt;And finally, we have a submit button that automatically calls the onSubmit of the parent form when it’s clicked or when the user hits return in the text field.&lt;/p&gt;

&lt;p&gt;All in all, it’s a combination of the mundane and the magical. This is just a simple client component that renders some data it gets back from a hook, and then has an input form that can send data to a server action. But wow, what we can do with this ui component tree that is returned from the server action (or API route)!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P-F9fvB3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AZosKtyj2yd-n5ilrC1u1NA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P-F9fvB3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AZosKtyj2yd-n5ilrC1u1NA.jpeg" alt="React Streamed Components Video Thumbnail" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;React Streamed Components Video Thumbnail&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;This nifty little experimental function in Vercel’s AI library opens up a world of possible dynamic server rendered UI. We’ve been talking about HTMX and how it puts rendering back into the server. Well, this implements a similar model but gives you even more power because the components returned from the server can be client components that are interactive. The client components returned from the server action can also access context defined in the application. That means that the dynamically returned client components can act just like any other component on the page! It’s very exciting!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>react</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Converting Figma To React the Fast and Easy Way</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Wed, 29 Nov 2023 16:01:37 +0000</pubDate>
      <link>https://dev.to/jherr/converting-figma-to-react-the-fast-and-easy-way-2mb5</link>
      <guid>https://dev.to/jherr/converting-figma-to-react-the-fast-and-easy-way-2mb5</guid>
      <description>&lt;p&gt;If you think that AI is going to replace web developers, look no further than trying to turn a Figma prototype into a working React application. Figma is a great tool for designers to build the UI of their dreams. But to turn those dreams into reality requires a lot of work.&lt;/p&gt;

&lt;p&gt;Step one of converting a mockup is to create the HTML. Thankfully, the folks at Figma added a “developer mode” earlier this year to help out. Developer mode allows for 3rd party plugins to turn Figma mockups into code. Those plugins have improved the quality of those exports immeasurably.&lt;/p&gt;

&lt;p&gt;There are a lot of plugins out there and they are continually improving. The best I’ve found so far is &lt;a href="https://dev.to/alex_builderio/introducing-visual-copilot-a-better-figma-to-code-workflow-31l2-temp-slug-2409097"&gt;Visual Copilot from Builder.io&lt;/a&gt; (the folks behind the Builder CMS, Qwik, Partytown, and more.) These are smart folks and this is a smart tool. It uses a custom built LLM to do the initial conversion and the results, in my opinion, get you about 80% of where you need to go with the HTML/CSS.&lt;/p&gt;

&lt;p&gt;Let’s take an example mockup for a home page and a product detail page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cG62geCQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AIYOmwUmmjfXiIpTR" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cG62geCQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AIYOmwUmmjfXiIpTR" alt="Two page eCommerce mockup in Figma" width="800" height="605"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Two page eCommerce mockup in Figma&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The mockup looks pretty good. There is the home page mockup on the right hand side and the detail page on the left.&lt;/p&gt;

&lt;p&gt;To start converting, we first switch the developer mode.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VhL3ght4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AJznmABXgKqrnfwL4" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VhL3ght4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AJznmABXgKqrnfwL4" alt="The developer mode toggle and Visual Copilot plugin in Figma" width="800" height="753"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The developer mode toggle and Visual Copilot plugin in Figma&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The big toggle switch at the top with the tag symbol moves us between designer and developer mode. Once we are in developer mode, we select the Plugins tab and search for the Builder.io plugin.&lt;/p&gt;

&lt;p&gt;Once we select the plugin, we then select a section of the mockup we want to export.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bi2_98le--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AQh-b7xv8ovEazuy4" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bi2_98le--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AQh-b7xv8ovEazuy4" alt="Selecting a portion of the Figma mockup to start the code generation process" width="800" height="494"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Selecting a portion of the Figma mockup to start the code generation process&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can select as much or as little as you like. For small pages, you could select the whole thing. For larger pages, you can select each section and export them individually to build up a set of components.&lt;/p&gt;

&lt;p&gt;I’ll just select the shoes hero section and then press the Generate code button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xBNjKYbo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2A3bmE1CVzXDKAuRml" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xBNjKYbo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2A3bmE1CVzXDKAuRml" alt="The generated React/Tailwind code in the Builder UI" width="800" height="538"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The generated React/Tailwind code in the Builder UI&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After just a few seconds of processing, I go into the Builder CMS UI that shows me the portion of the mockup I exported and the code at the bottom of the page.&lt;/p&gt;

&lt;p&gt;Don’t worry if you aren’t using the Builder CMS in your application as you can just copy and paste the code from here into your own application.&lt;/p&gt;

&lt;p&gt;Before we get into the generated code, it’s worth noting a few things.&lt;/p&gt;

&lt;p&gt;At the top of the preview section is a selector where you can toggle between desktop, tablet, and mobile preview sizes. Visual Copilot generating responsive code that works at different breakpoints and the Builder CMS previewing the common breakpoints is a massive time saver.&lt;/p&gt;

&lt;p&gt;In the code section, there are selectors for Framework and Styling. You can choose between all the common Frameworks: React, Vue, Svelte, Angular, Qwik, etc. Then you can choose between different Styling options like Tailwind, Emotion, Styled Components and more.&lt;/p&gt;

&lt;p&gt;There is also a Fast versus Quality toggle. The Fast variant is free… and very fast. While the Quality version (which is a pay-for option) runs an extra GPT pass to try and further refine the code to produce more semantically structured results.&lt;/p&gt;

&lt;p&gt;The Quality version also allows for AI refinement.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O1nLYxR_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AY3i0S_EBzsfp_3H0" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O1nLYxR_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AY3i0S_EBzsfp_3H0" alt="The AI refinement section presented in the “Quality” mode of the Visual Copilot" width="800" height="383"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The AI refinement section presented in the “Quality” mode of the Visual Copilot&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At the bottom of the display, you can have GPT further refine the code based on whatever prompt you give it. They even have some handy suggestions, like using NextJS’s Image component instead of using &lt;a href="" class="article-body-image-wrapper"&gt;&lt;img&gt;&lt;/a&gt; tags directly.&lt;/p&gt;

&lt;p&gt;Finally, there is the copy button that you’ll want to use to get the code into your application.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://youtu.be/DttZuqAiuR0"&gt;video associated with this article&lt;/a&gt;, I’ll walk you through the entire process of converting this set of pages into a NextJS application–including extracting all of the images from the Builder CDN to local files in public and converting the &lt;a href="" class="article-body-image-wrapper"&gt;&lt;img&gt;&lt;/a&gt; tags to Image components. I’ve built a &lt;a href="https://gist.github.com/jherr/14cf3143ab1dc40ebc8a29d992c71419"&gt;little script&lt;/a&gt; for this that you are welcome to use.&lt;/p&gt;

&lt;p&gt;As I mentioned at the start of this article, this process will prove to you that AI is never going to do all the work required to turn mockups into production applications. Which seems odd, given that I then went on to cover an AI tool that does just that. Or does it? Turns out there is a lot left to be done by web developers to get to production.&lt;/p&gt;

&lt;h3&gt;
  
  
  It’s Not Always This Easy
&lt;/h3&gt;

&lt;p&gt;The first issue is that these Figma-mocked UIs are not always this easy to work with. The example I used was a reasonable design. However, the reason that web developers have a love/hate relationship with Figma is that Figma allows designers to do &lt;em&gt;anything they want&lt;/em&gt;, including creating very hard to implement designs.&lt;/p&gt;

&lt;p&gt;AI tools will get you really far with reasonable designs, but for the weirder stuff they will get you a certain distance and then it’s all on you to not just implement, but also to negotiate with designers on what’s reasonably achievable and what’s not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Responsiveness
&lt;/h3&gt;

&lt;p&gt;As I mentioned, Visual Copilot does a decent job of doing responsive layout of a well-designed mockup. But there are often times when the mobile version of a UI will vary widely from the desktop version, and web developers will need to make up that gap. Take the navigation menu in the header:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3YIZyENH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AEHHuZJZ_ogsHiC8B" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3YIZyENH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2AEHHuZJZ_ogsHiC8B" alt="The navigation portion of the header in both desktop and mobile mode" width="800" height="143"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The navigation portion of the header in both desktop and mobile mode&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We only had the desktop version of the navigation menu in the mockup, so the AI did what it could with that and created a menu that scales really nicely down to mobile. But maybe the customer doesn’t want that, maybe they want a &lt;a href="https://www.w3schools.com/howto/howto_js_mobile_navbar.asp"&gt;hamburger menu&lt;/a&gt; for mobile. It’s going to be up to the designer, product manager, and developer to work all that out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Reuse
&lt;/h3&gt;

&lt;p&gt;Probably the biggest issue I’ve seen with Figma mockups is that they rarely point out when we intend to reuse a component or what that reused component is supposed to be. Take these two sections of the mockup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---mYlbGmd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2A20mC_xNJLrq3T9af" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---mYlbGmd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/0%2A20mC_xNJLrq3T9af" alt="The same carousel on both the home page and the product detail page" width="800" height="277"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The same carousel on both the home page and the product detail page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One version says “Featured Products”, the other section on the detail page says “You may also like”, but the carousel style UI underneath certainly looks the same in both cases. So, can these sections be reused? Should they be reused? These are choices that can only be made in conversation with the product manager and designer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Full Implementation
&lt;/h3&gt;

&lt;p&gt;Of course, the 800lb gorilla in the room is to make it actually functional. Obviously, this means wiring up the data to make it all data driven. As well as integrating the eCommerce functionality required to allow the customer to actually buy the shoes. And on top of that, there is accessibility and internationalization.&lt;/p&gt;

&lt;p&gt;That’s just to implement what we see in the mockup. There is often hidden functionality we don’t see, like low data states, or functionality that is implied but not rendered in the mockup, like the carousel for “Featured Products”. Does that always take four products? Does it scroll on the desktop? Does it flick on mobile?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CIb1L-nI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AlTszsilCZwh1E6l_mEYjjw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CIb1L-nI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AlTszsilCZwh1E6l_mEYjjw.jpeg" alt="Thumbnail for the video associated with this article" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Thumbnail for the video associated with this article&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;The great part about what’s left over after Visual Copilot has given you a fantastic start on the code is the fun part of engineering. That’s the great part about these AI tools. They aren’t meant to replace you. They are meant to take the tedious jobs, like converting a Figma mock into some reasonable HTML, and do those for you so that as a developer, you can focus on what you do best.&lt;/p&gt;

&lt;p&gt;Personally, I’m endlessly fascinated by every part of UI, from design through to implementation. So, I’ve been working with Figma mocks and designers for years. I’m always on the lookout for tools that will help accelerate the process of going from a mockup to an app because I love seeing projects come to life. I strongly recommend trying out Figma plugins to help accelerate your workflow. And if you are looking for a plugin to go from Figma to React/Tailwind (and lots of other variations), Visual Copilot is the best plugin I’ve seen for doing that work.&lt;/p&gt;

&lt;p&gt;Jack Herrington is a Principal Full Stack Engineer and &lt;a href="https://www.youtube.com/@jherr"&gt;YouTuber&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
He is currently writing a course on &lt;a href="https://www.pronextjs.dev/"&gt;Professional NextJS&lt;/a&gt;. Sign up for the free newsletter and get a full free tutorial on state management in the NextJS App Router.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ui</category>
      <category>figma</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>How Do I Obscure API Keys On The Client?</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Thu, 03 Aug 2023 16:39:31 +0000</pubDate>
      <link>https://dev.to/jherr/how-do-i-obscure-api-keys-on-the-client-5mk</link>
      <guid>https://dev.to/jherr/how-do-i-obscure-api-keys-on-the-client-5mk</guid>
      <description>&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt; : How do I obscure API keys on the client?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt; : So you have a super powerful key to a 3rd party API that allows you to read/write any data you want from any customer, and you don’t want that falling into anyone else’s hands. What do you do? Gotcha. First off, you never send that to the client, not in any way, not obscured, not encrypted, not anything. Because try as you might to hide it, the key will end up showing clear as day in the Network tab of the Inspector as soon as you make a call on the client.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Y1TQhan--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Aw03XojOiHkHkZ0o3e9dISw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Y1TQhan--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Aw03XojOiHkHkZ0o3e9dISw.jpeg" alt="" width="800" height="534"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;React + NextJS Questions And Answers Banner&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What you should do instead is create a &lt;em&gt;proxy&lt;/em&gt; API endpoint on your NextJS server. NextJS has always had great support for making API routes. You can use a &lt;a href="https://nextjs.org/docs/app/building-your-application/routing/route-handlers"&gt;route handler&lt;/a&gt; to create a proxy endpoint that will take the request from the client, and then make the request to the 3rd party API on the server. This way, the client never sees the API key, and you can do whatever you want with the response before sending it back to the client.&lt;/p&gt;

&lt;p&gt;This &lt;em&gt;proxy&lt;/em&gt; API also doesn’t need to be a 1-to-1 proxy, you can create an abstraction layer that allows you to do things like caching, or rate limiting, or even just to make the API easier to use. For example, if you have a 3rd party API that requires you to make 3 separate calls to get the data you need, you can create a single endpoint that makes those 3 calls and returns the data in a single response. In addition this new API ensures that if you want to change out that 3rd party API layer later that you only have to change it in one place.&lt;/p&gt;

&lt;p&gt;To be honest, learning how to make the calls from a NextJS route handler will teach you how to make the calls to the API during Server Side Rendering, which is probably what you want to do anyway. So learning this technique of building proxy APIs is a two-fer!&lt;/p&gt;

&lt;p&gt;Before you do any of this, make sure that the API key is indeed dangerous to be on client. Not all API keys are meant to be kept secret. Some keys, like Firebase keys, are meant to be used on the client. If you’re not sure, check the documentation for the API you’re using.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Jack Herrington is currently working on a&lt;/em&gt; &lt;a href="https://pronextjs.dev/"&gt;&lt;em&gt;course on NextJS&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, subscribe to the newsletter to get updates as well as React and NextJS tips, tricks and tutorials.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>tips</category>
    </item>
    <item>
      <title>Why Not Just Fetch All The Data From The Client?</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Thu, 03 Aug 2023 00:50:00 +0000</pubDate>
      <link>https://dev.to/jherr/why-not-just-fetch-all-the-data-from-the-client-57nl</link>
      <guid>https://dev.to/jherr/why-not-just-fetch-all-the-data-from-the-client-57nl</guid>
      <description>&lt;p&gt;&lt;strong&gt;Question&lt;/strong&gt; : With my NextJS application, why not just fetch all the data from the client? Why do we need to fetch data on the server?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Y1TQhan--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Aw03XojOiHkHkZ0o3e9dISw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Y1TQhan--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Aw03XojOiHkHkZ0o3e9dISw.jpeg" alt="" width="800" height="534"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;React + NextJS Questions and Answers banner&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt; : There are several key advantages to fetching data on the server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It’s Usually Faster&lt;/strong&gt;  — NextJS servers are usually deployed in the same Virtual Private Cloud (VPC) or cluster as the microservices they call. This means that the network latency between the NextJS server and the microservices is very low. This is not the case for requests from the client. A customer web client can be anywhere, and the network latency between the client and the microservices is much higher. This means that fetching data on the server is usually faster than fetching it on the client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microservices Stay Behind the Firewall&lt;/strong&gt;  — If only the NextJS server (or other microservices) can talk to the microservices then those microservices can stay behind the firewall. This means the surface area of attacks is limited to just the NextJS server itself. To make the API calls from the client we would have to expose the microservices to the public internet, which expands the security risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Keys Are Hidden&lt;/strong&gt;  — If we are using third party serivces as part of our application then those probably have API keys. Those keys should never go out to the client. Making the requests only from the NextJS server ensures that those keys are hidden.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search Engine Optimization&lt;/strong&gt;  — Server side rendering, where the server renders HTML in response to a request, has long been the preferred choice of Search Engine Optimization (SEO) professionals. It is an arguable point that nowadays search engines can index client side rendered pages, but if you have a site where SEO is an important point then most likely they will prefer the SEO relevant portions of the site to be server side rendered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not to say that client side fetching is a bad thing, it’s not. There are many cases where client side fetching is the right choice. But if you are building a NextJS application then you should consider server side fetching as the default choice.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Jack Herrington is currently working on a &lt;a href="https://pronextjs.dev"&gt;course on NextJS&lt;/a&gt;, subscribe to the newsletter to get updates as well as React and NextJS tips, tricks and tutorials.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>architecture</category>
      <category>nextjs</category>
      <category>tips</category>
      <category>react</category>
    </item>
    <item>
      <title>Does NextJS SSR Render Just the VDOM Nodes?</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Thu, 03 Aug 2023 00:45:09 +0000</pubDate>
      <link>https://dev.to/jherr/does-nextjs-ssr-render-just-the-vdom-nodes-5c6d</link>
      <guid>https://dev.to/jherr/does-nextjs-ssr-render-just-the-vdom-nodes-5c6d</guid>
      <description>&lt;h3&gt;
  
  
  Does NextJS SSR Render Just The VDOM Nodes?
&lt;/h3&gt;

&lt;p&gt;One of the great things about running a coding &lt;a href="https://youtube.com/@jherr"&gt;YouTube channel&lt;/a&gt; are the amazing questions that I get that give me some insights into how folks are thinking about React and NextJS. One recent question was about the NextJS App Router and whether it renders only VDOM or if it renders the entire page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Y1TQhan--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Aw03XojOiHkHkZ0o3e9dISw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Y1TQhan--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2Aw03XojOiHkHkZ0o3e9dISw.jpeg" alt="" width="800" height="534"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;React + Next Questions and Answers banner&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt; : The App Router renders the requested route into &lt;strong&gt;both&lt;/strong&gt; the Virtual DOM (VDOM) and the HTML. The HTML is what the customer sees on the page, and the VDOM is used to initialize the React Virtual DOM on the client.&lt;/p&gt;

&lt;p&gt;There are three ways you can see exactly what’s coming out of your NextJS server for a given route. You can &lt;code&gt;curl&lt;/code&gt; it on the command line using a command like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you don’t like the command line you can right click on the page in the browser and select View Page Source. The page source is exactly what came back from the server. It is not a live view of the current DOM of the page.&lt;/p&gt;

&lt;p&gt;A third way is to bring up the inspector in your browser, select the Network tab, and then refresh the page. The first item in the list will be a GET request for the current route and the response is the HTML that came back from the server. You can click on that item and then select the Preview tab to see the HTML.&lt;/p&gt;

&lt;p&gt;The response from the server looks pretty bad because all of the whitespace is removed between the tags, so it will all be on one line. In the browser if you are viewing the page source you can click on the Line Wrap option to at least see all the HTML.&lt;/p&gt;

&lt;p&gt;At the top you will see the rendered HTML of the components. Below that is a &lt;strong&gt;large&lt;/strong&gt; set of script tags that set up the Virtual DOM on the client. Those aren’t really VDOM nodes per se, they are a combination of component references, props, rendered DOM nodes, and other information that is used to initialize the client side VDOM.&lt;/p&gt;

&lt;p&gt;If you want you can analyze that VDOM section further using this &lt;a href="https://rsc-parser.vercel.app"&gt;RSC Parser tool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I can understand why you might think the server only generates VDOM nodes since React does so much client side rendering. But believe me, if the server only generated VDOM nodes then the page would be blank, and search engines would have nothing to index if they only looked at the HTML. That would give Search Engine Optimization folks a heart attack.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Jack Herrington is currently working on a &lt;a href="https://pronextjs.dev"&gt;course on NextJS&lt;/a&gt;, subscribe to the newsletter to get updates as well as React and NextJS tips, tricks and tutorials.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>react</category>
      <category>tips</category>
      <category>short</category>
    </item>
    <item>
      <title>App Router Secret: Promises for Client Component Props</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Tue, 01 Aug 2023 01:49:03 +0000</pubDate>
      <link>https://dev.to/jherr/app-router-secret-promises-for-client-component-props-1pgp</link>
      <guid>https://dev.to/jherr/app-router-secret-promises-for-client-component-props-1pgp</guid>
      <description>&lt;p&gt;We know that we can send objects, arrays, strings, numbers, dates and more value types as properties from a React Server Component (RSC) to a client component, but did you know you can send a promise? You can use the new use hook to block on the promise inside the client component!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Hxukev8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AmBLQEiF7Q5LWbZ7fxIra1w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Hxukev8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AmBLQEiF7Q5LWbZ7fxIra1w.jpeg" alt="" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To see this in action be sure to check out the YouTube video:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ViVa5JPGrf4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In the video we demonstrate not just using the use hook but also using the popular React-Query library because with React-Query (or SWR) you can track a promise.&lt;/p&gt;

&lt;p&gt;Let’s dig a little deeper into the React-Query use case by showing you also how to refetch data from the client component on the browser! You can go through the code yourself in this &lt;a href="https://github.com/jherr/rsc-rq-timer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the API
&lt;/h3&gt;

&lt;p&gt;Our simple NextJS App Router application is going to be a timer. When it’s completed it will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--if_sZrdz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2A8vSwCnHYMumISN_D8lc0ng.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--if_sZrdz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://cdn-images-1.medium.com/max/800/1%2A8vSwCnHYMumISN_D8lc0ng.gif" alt="" width="800" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ll get that timestamp from an API endpoint on /api/timer . The code for the endpoint is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;NextResponse&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;next/server&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&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;NextResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&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 home route page component is what makes the request to the API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="nf"&gt;Home&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;timerPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;http://localhost:3000/api/timer&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="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-cache&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="nf"&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="p"&gt;)&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;max-w-3xl mx-auto mt-5&lt;/span&gt;&lt;span class="dl"&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;RQTimer&lt;/span&gt; &lt;span class="nx"&gt;timerPromise&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;timerPromise&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&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;At the top we make the request to /api/timer but we don’t await it, and that’s important because we can pass that promise to the RQTimer client component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using The Use Hook For Promise Data
&lt;/h3&gt;

&lt;p&gt;Let’s start our client component off by just using the use hook to get the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;use&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="nf"&gt;FoodList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;timerPromise&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="nl"&gt;timerPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&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;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timerPromise&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-light text-xl mb-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;RQ&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;RSC&lt;/span&gt; &lt;span class="nx"&gt;Timer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-extrabold text-3xl&lt;/span&gt;&lt;span class="dl"&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;time&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toString&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&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The use hook is a new hook that, given a promise, will monitor that promise once it’s fulfilled will force a re-render of the component and then return the time which we format into some decent looking Tailwind.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Didn’t know that you could send a promise as a property? Keep up with these kinds of NextJS tips and tricks by &lt;a href="https://pronextjs.dev"&gt;subscribing to the ProNextJS newsletter&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that’s all well and good, but let’s say we are React-Query fans, can we use that instead? Sure we can!&lt;/p&gt;

&lt;h3&gt;
  
  
  Using React Query Instead of Use
&lt;/h3&gt;

&lt;p&gt;To use React-Query we need to wrap the page in a QueryProvider (&lt;a href="https://github.com/jherr/rsc-rq-timer/blob/main/app/page.tsx#L10-L14"&gt;shown in the repo code&lt;/a&gt;). Then we can use useQuery in our RQTimer component like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useQuery&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;@tanstack/react-query&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="nf"&gt;FoodList&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;timerPromise&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="nl"&gt;timerPromise&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&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="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timer&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="nx"&gt;timerPromise&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-light text-xl mb-2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;RQ&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;RSC&lt;/span&gt; &lt;span class="nx"&gt;Timer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-extrabold text-3xl&lt;/span&gt;&lt;span class="dl"&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;time&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toString&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&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The useQuery hook requires two parameters. First the query key, which is just a unique key to describe the request, in this case we use timer . And then a function that makes the request, and for that we can just give it a function that returns the timerPromise that we got as a property.&lt;/p&gt;

&lt;p&gt;So easy!&lt;/p&gt;

&lt;p&gt;But… what if we want to re-fetch that API endpoint once a second? To do that we can use React-Query’s fetchInterval option!&lt;/p&gt;

&lt;h3&gt;
  
  
  Using FetchInterval To Refetch The API On The Client
&lt;/h3&gt;

&lt;p&gt;So first off we need to only run the refetch of the /api/time API on the client. So we’ll need to use a useEffect to set a flag that we can use to tell if we are on the client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientLoaded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&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="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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timer&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="nx"&gt;timerPromise&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&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;clientLoaded&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we declare a clientLoaded ref and then set it in the useEffect. Then in our useQuery query function we check that clientLoaded ref.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&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="s2"&gt;timer&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientLoaded&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="nf"&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;http://localhost:3000/api/timer&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="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-cache&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="nf"&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="p"&gt;)&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="nf"&gt;json&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;timerPromise&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;refetchInterval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&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;If the clientLoaded ref is true then we know we are on the client and we get the data from the API, otherwise we are on the server (or in the first render on the client) and we return the original timerPromise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Manually Refetching
&lt;/h3&gt;

&lt;p&gt;In this case we are using the refetchInterval to make a new fetch to the API every second. But if you want you can force the refetch manually by getting the refetch function in the return of the useQuery hook. Then, whenever you want to refetch on the client just call that function.&lt;/p&gt;

</description>
      <category>serversiderendering</category>
      <category>react</category>
      <category>typescript</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Five Clever Hacks for React-Query or SWR</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Tue, 05 Jul 2022 14:52:36 +0000</pubDate>
      <link>https://dev.to/jherr/five-clever-hacks-for-react-query-or-swr-anf</link>
      <guid>https://dev.to/jherr/five-clever-hacks-for-react-query-or-swr-anf</guid>
      <description>&lt;p&gt;So dealing with the double-render issue in React 18 has finally gotten you to use a API handling library like &lt;a href="https://react-query.tanstack.com/" rel="noopener noreferrer"&gt;react-query&lt;/a&gt; or &lt;a href="https://swr.vercel.app/" rel="noopener noreferrer"&gt;swr&lt;/a&gt;. Awesome! But did you know you can get more out of that 12Kb (or 4Kb in the case of swr) than just API fetching? Here are five pretty novel uses for these awesome libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prefer a Video?
&lt;/h3&gt;

&lt;p&gt;If you prefer to watch your technical story then have a &lt;a href="https://www.youtube.com/watch?v=JaM2rExmmqs&amp;amp;feature=youtu.be&amp;amp;ab_channel=JackHerrington" rel="noopener noreferrer"&gt;watch over on YouTube&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplified Multiple Fetches
&lt;/h3&gt;

&lt;p&gt;We tend to think of a useQuery hook as one hook per fetch. But let’s say you have two fetches to make. For example you have a login system where you first fetch to do the login and then fetch again to get the user information once you have their user ID.&lt;/p&gt;

&lt;p&gt;You might start with something like this:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useQuery&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-query&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;fetchLogin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&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;/login.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&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;fetchUser&lt;/span&gt; &lt;span class="o"&gt;=&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="nf"&gt;fetch&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;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.json`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&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;MyComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
 &lt;span class="kd"&gt;const&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="nx"&gt;login&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchLogin&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="na"&gt;data&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&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="nf"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;login&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;login&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="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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this model we cascade these two useQueryhooks. First we get the login, and then once the login is returned with a non-zero id then we enable the second query. Now… this works. But such pain! And imagine if it were more complex with three or more requests. There has to be a better way!&lt;/p&gt;

&lt;p&gt;There is of course, we can just make a login function, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&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;/login.json&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="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;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;userResp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&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;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.json`&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;user&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;userResp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;user&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;And use that instead in our component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
 &lt;span class="kd"&gt;const&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="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;login&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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 see, useQuery monitors any function, it could be a single fetch or it could be a function like this that makes multiple fetches with logic and such. Or it might not be a fetch at all (as we will soon see.) The point here is to start thinking outside the fetch box.&lt;/p&gt;

&lt;p&gt;But before we leave the topic of fetch lets look at just two more handy variants.&lt;/p&gt;

&lt;p&gt;For example, if you have an array of fetches to make in series you could do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getTextData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;for &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;name&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;c&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;const&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/data_&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="s2"&gt;.json`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;out&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="kd"&gt;const&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="nx"&gt;textData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;textData&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getTextData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case we are using a for loop to iterate through an array of values and then requesting the JSON for each of them before returning it all. BTW, if you like this example but don’t like for and you replace it with forEach it won’t work and that’s because forEach isn’t compatible with async/await , but hey, try it for yourself and enjoy.&lt;/p&gt;

&lt;p&gt;If you wanted to do this in parallel you might try something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getTextData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&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="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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="o"&gt;=&amp;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;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/data_&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="s2"&gt;.json`&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;await&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;This will also work, but I don’t think the order of results is guaranteed, it will depend on how fast the individual fetches resolve.&lt;/p&gt;

&lt;p&gt;I hear you screaming: “Enough with fetching! Show me something new!” Fine, fine!&lt;/p&gt;

&lt;h3&gt;
  
  
  Keeping Track Of Time
&lt;/h3&gt;

&lt;p&gt;Let’s make a stopwatch using SWR. No, I’m not kidding!&lt;/p&gt;

&lt;p&gt;We’ll start by create a functor (a function that makes functions) and this functor will make use a function that knows the time at which it was created. And then when we call it, it will return the delta between that start time and the current time, in seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createStopwatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&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;Now when we call createStopwatch we will get a function back that knows its start time and will give us the elapsed time since then. And we can use that in a component with that uses the useSWR hook, like so:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useSWR&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;swr&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;Stopwatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stopwatchRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createStopwatch&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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSWR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stopwatch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stopwatchRef&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="na"&gt;refreshInterval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dedupingInterval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&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="na"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;:&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="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 start by creating a ref to hold the function, which, because we use useRef will only get called once on mount. Then we use that function (by getting it from stopwatchRef.current) in the useSWR hook, which calls that function every 100 milliseconds because of the refreshInterval.&lt;/p&gt;

&lt;p&gt;That’s it! Boom! A stopwatch! We are using the refresh interval built into SWR to, instead of fetching data every hundred milliseconds, to instead call this synchronous function.&lt;/p&gt;

&lt;p&gt;Now this is cool and all, but not really practical, let’s try something related but more practical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitor Those Logs!
&lt;/h3&gt;

&lt;p&gt;Let’s say you want part of the UI to monitor a log. And the log updates a &lt;strong&gt;lot&lt;/strong&gt; , like easily every 100 milliseconds. But you don’t want to update the UI that often because, let’s face it, the log isn’t that important. So can we use react-query (or SWR) to throttle the update speed? Sure we can!&lt;/p&gt;

&lt;p&gt;First, let’s simulate a log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscribeToLog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;logIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;setInterval&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;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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;logIndex&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="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;logIndex&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="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;log&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;logListener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;subscribeToLog&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have a logListener global that is a function that returns the log messages that are continuously being built by the interval function. Every 100 milliseconds that interval adds a new log message and then trims the log down to the most recent three events (just to keep the display size small.)&lt;/p&gt;

&lt;p&gt;Now we use react-query to fetch the log, but only once every second:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useQuery&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-query&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;Logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;log&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logListener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;refetchInterval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&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;line&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;line&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&lt;/span&gt;&lt;span class="err"&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="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&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;In this case we are using the useQuery hook to poll the logListener (which returns the last three items in the log) every 1000 milliseconds (1 second). And that throttles the display so that we don’t update it too often.&lt;/p&gt;

&lt;p&gt;Of course, the swr code is dramatically different. You have to change refetchInterval to refreshInterval and add that dedupingInterval . It’s crazy, I know, the differences are staggering.&lt;/p&gt;

&lt;p&gt;Ok, so that really was a different use for something like react-query or swr, but what else have I got? How about getting GPS coordinates!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AXh8aAO_qTOqDTMq4GmZAqQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AXh8aAO_qTOqDTMq4GmZAqQ.jpeg"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Five Clever Hacks for React-Query and SWR image&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Going Home With GPS
&lt;/h3&gt;

&lt;p&gt;Anything you can wrap in a promise you can monitor with these awesome libraries. Take getting your GPS coordinates for example. Here we wrap the browsers built-in getCurrentPosition in a promise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getGPSCoordinates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&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="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;geolocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&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="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;longitude&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;error&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="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;And then we can call it, with… lemme just pick one… swr this time:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useSWR&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;swr&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;GPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="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="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSWR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gps&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getGPSCoordinates&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="na"&gt;Location&lt;/span&gt;&lt;span class="p"&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="nf"&gt;stringify&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="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;And there you go, GPS coordinates in your component.&lt;/p&gt;

&lt;p&gt;The key point here is that; anything you can turn into a synchronous function, or a promise based async function, is going to work with these libraries. &lt;strong&gt;Anything&lt;/strong&gt;. At all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parallelize With Web Workers
&lt;/h3&gt;

&lt;p&gt;Which brings me to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" rel="noopener noreferrer"&gt;Web Workers&lt;/a&gt;, which are really handy bits of code that you can run in a different thread on the page. Take a simple one like this:&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multiplyNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;result&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;result&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="nx"&gt;b&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;This little guy can multiple two numbers and send back the result. Such a good little function! Anyway, we can integrate it into our code super simple using react-query (or swr). We first need to load it:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;worker&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;workerize-loader!./worker&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;workerInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have an instance of the worker that we have loaded using the workerize-loader Webpack loader. We can then wrap that in a promise based function which calls it, waits for the result, and then resolves the promise with the output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;multiplyNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&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="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;workerInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&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;message&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;message&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;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;result&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="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&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;result&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;workerInstance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multiplyNumbers&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;a&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;b&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;All we do is create a promise, register a listener on the instance, then make the call. Once the listener fires we have our result. And here is the component code that uses this function, this time using react-query.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMutation&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-query&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;WebWorker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mutate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;multiply&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;multiplyNumbers&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;valueA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValueA&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;valueB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValueB&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;20&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
        &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;valueA&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setValueA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
        &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;valueB&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setValueB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;mutate&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="nx"&gt;valueA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;valueB&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Multiply&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&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;In this case I’m using the useMutation hook from react-query because it makes a little more sense in that it’s actively executing something. And that’s kind of important as you look to perhaps use some of these patterns; make sure your queries are modeled as useQuery and that actions that potentially change things use the useMutation hook.&lt;/p&gt;

&lt;p&gt;Of course that doesn’t help you with swr, that doesn’t have a mutation hook, but there is still a way to do this with swr as well.&lt;/p&gt;

&lt;p&gt;Now, let’s finish this off in grand style, by answering the age old question; if you have react-query or swr, do you need a state manager?&lt;/p&gt;

&lt;h3&gt;
  
  
  Built-In State Manager?!?
&lt;/h3&gt;

&lt;p&gt;Both swr and react-query manage caches, right? They can both make sure that if you access the same query key from two different spots you’ll get the same data.&lt;/p&gt;

&lt;p&gt;Which means that you can use that cache to store bits of data you want, globally, and when you update them, they will update everywhere they are “subscribed”. Which is like … 80%? of what a state manager does?&lt;/p&gt;

&lt;p&gt;So we can create a custom hook called useSWRGlobalState that does exactly this global shared stuff, check it out.&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useSWR&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;swr&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;useSWRGlobalState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialData&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="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;mutate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSWR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;initialData&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="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;initialData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nf"&gt;mutate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;revalidate&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You give this hook a key , which is the query key we’ve been using all of over the place, and whatever you want for the initial data. And it in turn uses useSWR to get the current data as well as the mutate function.&lt;/p&gt;

&lt;p&gt;The hook then returns an array that looks like the return from useState . It is an array where the first item is the current value, and the second is a setter function.&lt;/p&gt;

&lt;p&gt;The setter function is where the magic happens. We call that mutate function we got back and give it the new value &lt;strong&gt;but&lt;/strong&gt; we tell swr &lt;strong&gt;not&lt;/strong&gt; to re-fetch the value. Which basically means; set the cache, but that’s all.&lt;/p&gt;

&lt;p&gt;Now we can wrap this in some components!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StateEditor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSWRGlobalState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sharedText&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="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="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="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StateViewer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSWRGlobalState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sharedText&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="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;value&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GlobalStateDemo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StateEditor&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;StateViewer&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="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&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;Here we have two separate components, one that edits the state, that’s the StateEditor component, and one that views the shared state, that being the StateViewer. When you type into the StateEditor the change shows up immediately in StateViewer .&lt;/p&gt;

&lt;p&gt;No kidding, really. No context. No Redux. No atoms. Just that one little hook, and the “fetch library” you already have.💥 Crazy, right?&lt;/p&gt;

&lt;p&gt;Now, would I use this for realsies? In a big application that maybe already has a state manager, then for sure not. But if all I needed to share around my component hierarchy was a single piece of state, like maybe the user ID, and a JWT, then yeah, I might just do this.&lt;/p&gt;

&lt;p&gt;BTW, this is possible with React-Query as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useRQGlobalState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialData&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="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;initialData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;enabled&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="nx"&gt;initialData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;initialData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setQueryData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This hook returns an array, just like before, where the first item in the array is the current value, that we get with useQuery and then second value is a setter function that sets the cache data for the query directly on the react-query client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping It Up
&lt;/h3&gt;

&lt;p&gt;I hope you’ve had a fun ride looking at a bunch of different ways you can wring more value out of the kilobytes you are adding to your app code by bringing in these awesome libraries. They really are an invaluable addition to the React ecosystem.&lt;/p&gt;




</description>
      <category>statemanagement</category>
      <category>javascript</category>
      <category>react</category>
      <category>swr</category>
    </item>
    <item>
      <title>React 18 useEffect Double Call for APIs: Emergency Fix</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Wed, 01 Jun 2022 02:37:18 +0000</pubDate>
      <link>https://dev.to/jherr/react-18-useeffect-double-call-for-apis-emergency-fix-27ee</link>
      <guid>https://dev.to/jherr/react-18-useeffect-double-call-for-apis-emergency-fix-27ee</guid>
      <description>&lt;p&gt;So you’ve upgraded to React 18, enabled &lt;a href="https://reactjs.org/docs/strict-mode.html" rel="noopener noreferrer"&gt;strict mode&lt;/a&gt;, and now all of your useEffects are getting called twice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F955%2F1%2AebSScvhXNYQjgEQJB4_P5Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F955%2F1%2AebSScvhXNYQjgEQJB4_P5Q.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;React 18 API Calls need an Emergency Fix!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Which would normally be fine, but you have API calls in your useEffects so you’re seeing double traffic in development mode. Sound familiar? No problem, I’ve got your back with a bunch of potential fixes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix #1: Live With It
&lt;/h3&gt;

&lt;p&gt;A legitimate option is simply to live with it, it’s dev-mode behavior only. It’s also trying to help you by stress testing your components to ensure they are compatible with future features in React. But, hey, I get it, you are here, you don’t like it, so … let’s just move on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix #2: Remove Strict Mode
&lt;/h3&gt;

&lt;p&gt;It is strict mode that is causing the double render, so another option is just to remove it. Out of the box the StrictMode component is used in index.js and it’s here:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

root.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;
);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So simply remove it, like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

root.render(&amp;lt;App /&amp;gt;);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That being said, I don’t recommend this route since strict mode does a lot of good checking on your app code so you really consider keeping it around.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix #3: Use An Abort Controller
&lt;/h3&gt;

&lt;p&gt;Another fix is to use an AbortController to terminate the request from the first useEffect . Let’s say this is your code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  const [people, setPeople] = useState([]);
  useEffect(() =&amp;gt; {
    fetch("/people")
      .then((res) =&amp;gt; res.json())
      .then(setPeople);
  }, []);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This code was fine (sort-of) in React 17, but strict mode in 18 is showing an issue by mounting, unmounting, and re-mounting your component in development mode. And this is showing off that you aren’t aborting the fetch if it hasn’t been completed before component un-mount. So let’s add that AbortController logic.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  useEffect(() =&amp;gt; {
    const controller = new AbortController();
    fetch("/people", **{  
      signal: controller.signal,  
    } )
      .then((res) =&amp;gt; res.json())
      .then(setPeople);
    return () =&amp;gt; controller.abort(); 
  }, []);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The code is pretty simple. We create a new AbortController then we pass its signal to the fetch and in our cleanup function we call the abort method.&lt;/p&gt;

&lt;p&gt;Now what’s going to happen is that the first request will be aborted but the second mount will not abort and the fetch will finish successfully.&lt;/p&gt;

&lt;p&gt;I think most folks would use this approach if it weren’t for one thing, that in the Inspector you see two requests where the first one is in red because it has been cancelled, which is just ugly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix #4: Create a Custom Fetcher
&lt;/h3&gt;

&lt;p&gt;A cool aspect of a JavaScript promise is that you can use it like a cache. Once a promise has been resolved (or rejected) you can keep calling then or catch on it and you’ll get back the resolved (or rejected) value. It will &lt;strong&gt;not&lt;/strong&gt; make a subsequent request on a fulfilled promise, it will just return the fulfilled result.&lt;/p&gt;

&lt;p&gt;Because of that behavior you can build a function that create custom cached fetch functions, like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const createFetch = () =&amp;gt; {
  // Create a cache of fetches by URL
  const fetchMap = {};

  return (url, options) =&amp;gt; {
    // Check to see if its not in the cache otherwise fetch it  
    if (!fetchMap[url]) {
      fetchMap[url] = fetch(url, options).then((res) =&amp;gt; res.json());
    }

    // Return the cached promise  
    return fetchMap[url];
  };
};


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This createFetch function will create a cached fetch for you. If you call it with the same URL twice, it will return the same promise both times. So you can make a new fetch like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

const myFetch = createFetch();


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And then use it in your useEffect instead of fetch with a simple replace:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  const [people, setPeople] = useState([]);
  useEffect(() =&amp;gt; {
    myFetch("/people").then(setPeople);
  }, []);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here is why this works. The first time the useEffect is called the myFetch starts the fetch and stores the promise in the fetchMap . Then the second time the useEffect function is called it the myFetch function returns the cached promise instead of calling fetch again.&lt;/p&gt;

&lt;p&gt;The only thing you need to figure out here is cache invalidation if you choose to use this approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix #5: Use React-Query
&lt;/h3&gt;

&lt;p&gt;None of this is a problem if you use &lt;a href="https://react-query.tanstack.com/" rel="noopener noreferrer"&gt;React-Query&lt;/a&gt;. React-Query is an amazing library that you should honestly be using anyway. To start with React-Query first install the react-query NPM package.&lt;/p&gt;

&lt;p&gt;From there create a query client and wrap your application in a QueryProvider component:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

import { QueryClient , QueryClientProvider } from "react-query";

...

const AppWithProvider = () =&amp;gt; (
  &amp;lt;QueryClientProvider client={new QueryClient()}&amp;gt;  
    &amp;lt;App /&amp;gt;
  &amp;lt;/QueryClientProvider&amp;gt;  
);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then in your component use the useQuery hook, like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  const { data: people } = useQuery("people", () =&amp;gt;
    fetch("/people").then((res) =&amp;gt; res.json())
  );


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Doesn’t that just look better anyway? And it doesn’t do the double fetch.&lt;/p&gt;

&lt;p&gt;This is just the tiniest fraction of what React-Query can do. And folks are using React-Query for more than just fetch, you can use it to monitor any promise-based asynchronous work you do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix #6: Use a State Manager
&lt;/h3&gt;

&lt;p&gt;I’m not going to go into code detail on this one since it depends a lot on the state manager you use. But if you use Redux then use then if you use the &lt;a href="https://redux-toolkit.js.org/rtk-query/overview" rel="noopener noreferrer"&gt;RTK Query functionality&lt;/a&gt; in Redux Toolkit you won’t be effected by this double-mount behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  What You Shouldn’t Do
&lt;/h3&gt;

&lt;p&gt;I strongly recommend against using useRef to try and defeat this behavior. There is no guarantee that the component that gets called on the first useEffect is the same one that gets called the second time around. So if you do things like use useRef to do tracking between mounts then… it’s unclear if that is going to work.&lt;/p&gt;

&lt;p&gt;Also the code that is currently going around to create a useEffectOnce doesn’t work. It does not call the cleanup function. Which is far worse behavior than having useEffect called twice.&lt;/p&gt;

&lt;h3&gt;
  
  
  What You Should Do
&lt;/h3&gt;

&lt;p&gt;If you like this content then you should check out my &lt;a href="https://www.youtube.com/c/JackHerrington" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt;. I cover topics like this all the time. In fact I’ve already covered the &lt;a href="https://youtu.be/j8s01ThR7bQ" rel="noopener noreferrer"&gt;useEffect topic already&lt;/a&gt; over there, but I haven’t covered the API call aspect specifically … yet.&lt;/p&gt;

</description>
      <category>reacthookuseeffect</category>
      <category>react18</category>
      <category>reactquery</category>
      <category>react</category>
    </item>
    <item>
      <title>React Apps with Plugins Using ScandiPWA</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Tue, 09 Feb 2021 15:41:02 +0000</pubDate>
      <link>https://dev.to/jherr/react-apps-with-plugins-using-scandipwa-1dle</link>
      <guid>https://dev.to/jherr/react-apps-with-plugins-using-scandipwa-1dle</guid>
      <description>&lt;p&gt;With the move to NodeJS we lost the architectural pattern of creating pluggable applications. Java application servers can be configured at runtime to override pluggable elements, like database drivers, etc. Can we get there with NodeJS? Yep! With the webpack plugin from ScandiPWA we can have our cake and eat it too!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S0XZWYh4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AFGqxT2BP-vu_DWhlRsKKbg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S0XZWYh4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AFGqxT2BP-vu_DWhlRsKKbg.jpeg" alt="" width="800" height="449"&gt;&lt;/a&gt;Banner Image&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up An App
&lt;/h3&gt;

&lt;p&gt;The first job is to set up a Create React App. Let’s do this in a directory called &lt;code&gt;scandi-test&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% &lt;span class="nb"&gt;mkdir &lt;/span&gt;scandi-test
% &lt;span class="nb"&gt;cd &lt;/span&gt;scandi-test
% yarn create react-app my-host-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that’s done we can go into the host application and update it to use &lt;code&gt;scandipwa-scripts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% &lt;span class="nb"&gt;cd &lt;/span&gt;my-host-app
% yarn add @scandipwa/scandipwa-scripts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that installed we can change the package.json to change the start and build scripts to be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scandipwa-scripts start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scandipwa-scripts build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"react-scripts eject"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are other tools that work like this; &lt;a href="http://@craco/craco"&gt;craco&lt;/a&gt;, and &lt;a href="http://react-app-rewired"&gt;react-app-rewired&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We then add a &lt;code&gt;scandipwa&lt;/code&gt; key to the &lt;code&gt;package.json&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"scandipwa"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"theme"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This registers the application as a host application. In &lt;a href="https://scandipwa.com/"&gt;ScandiPWA&lt;/a&gt; parlance this is called a “theme” because ScandiPWA is a company that produces a theme for Magento, and this plugin extensibility layer allows ScandiPWA customers the ability to customize that theme down to the function, class, member variable, and more, level.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making The App Extensible
&lt;/h3&gt;

&lt;p&gt;Now that our Create React App based application is enabled for ScandiPWA plugin it’s time to make it extensible. Over in &lt;code&gt;App.js&lt;/code&gt; let’s create a new function called &lt;code&gt;getData&lt;/code&gt; and define it like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** @namespace my-host-app/getData */&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And lets re-define our &lt;code&gt;App&lt;/code&gt; React component like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="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="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getData&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&lt;/span&gt;&lt;span class="err"&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;Is this going to be pretty? Heck no! But we aren’t concerned with looks, we want that yummy functionality. So let’s get to building out our extension.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building The Extension
&lt;/h3&gt;

&lt;p&gt;In the parent directory of &lt;code&gt;my-host-app&lt;/code&gt; we create a peer directory called extension and initialize it as an NPM repo with some directories like 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;mkdir &lt;/span&gt;extension
% &lt;span class="nb"&gt;cd &lt;/span&gt;extension
% yarn init &lt;span class="nt"&gt;-y&lt;/span&gt;
% &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; src/plugin
% &lt;span class="nb"&gt;touch &lt;/span&gt;src/plugin/extension.plugin.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where it starts getting good! Next let’s define our plugin by updating the contents of &lt;code&gt;extension.plugin.js&lt;/code&gt; to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-host-app/getData&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="na"&gt;function&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="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enabling the Extension
&lt;/h3&gt;

&lt;p&gt;Now we can go back to the &lt;code&gt;package.json&lt;/code&gt; of &lt;code&gt;my-host-app&lt;/code&gt; and enable the extension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"scandipwa"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"theme"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"extension"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will enable the extension. And while we are in &lt;code&gt;package.json&lt;/code&gt; let’s go to dependencies and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"extension"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"link:../extension"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So let’s start up your application and see where we’ve gotten to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% &lt;span class="nb"&gt;cd &lt;/span&gt;my-host-app
% yarn
% yarn start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That first yarn establishes the link with the extension project and the second one launches the application.&lt;/p&gt;

&lt;p&gt;If everything works you should see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k1XnhLwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/752/1%2AwArfFqKy-15QIPYa8ilsMA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k1XnhLwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/752/1%2AwArfFqKy-15QIPYa8ilsMA.png" alt="" width="752" height="288"&gt;&lt;/a&gt;The override data shown in the host application&lt;/p&gt;

&lt;p&gt;I know it doesn’t look like much. But think about the potential. You can mark anything in your application is extensible and have one or more extensions installed that override the functionality.&lt;/p&gt;

&lt;p&gt;Right now with this tooling &lt;a href="https://docs.create-scandipwa-app.com/extensions/application-plugins"&gt;you can override&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Functions (as we did)&lt;/li&gt;
&lt;li&gt;Classes&lt;/li&gt;
&lt;li&gt;Static member variables&lt;/li&gt;
&lt;li&gt;Member variables&lt;/li&gt;
&lt;li&gt;Member functions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where To Go Next
&lt;/h3&gt;

&lt;p&gt;One the Blue Collar Coder channel we have a video that walks through getting this all working using a far more interesting example. Go have a look!&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/87hg99a9cjE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;Pluggable architectures are a great way to move your highly verticalized application to something that is an extensible platform that folks can customize to match their requirements. This ScandiPWA webpack plugin (which can be used outside of CRA) allows you to specify extension points and override their functionality. That gives you a great new architectural tool for NodeJS applications.&lt;/p&gt;

</description>
      <category>node</category>
      <category>architecture</category>
      <category>scandipwa</category>
      <category>react</category>
    </item>
    <item>
      <title>Mastering Typescript for React Hooks</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Wed, 03 Feb 2021 15:43:05 +0000</pubDate>
      <link>https://dev.to/jherr/mastering-typescript-for-react-hooks-me5</link>
      <guid>https://dev.to/jherr/mastering-typescript-for-react-hooks-me5</guid>
      <description>&lt;h3&gt;
  
  
  Mastering TypeScript for React Hooks
&lt;/h3&gt;

&lt;p&gt;So you want to use TypeScript in your React application, but even the hooks are giving you grief. Well, let’s get you comfortable with how to use TypeScript typing with those hooks and get you on your way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A8BEPuAzdDn1WqkM1P-sgew.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2A8BEPuAzdDn1WqkM1P-sgew.jpeg"&gt;&lt;/a&gt;Banner image&lt;/p&gt;

&lt;p&gt;This article is meant to supplement the excellent &lt;a href="https://github.com/typescript-cheatsheets/react" rel="noopener noreferrer"&gt;React TypeScript Cheat Sheet&lt;/a&gt; which you should definitely take a look at.&lt;/p&gt;

&lt;h3&gt;
  
  
  useState
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;useState&lt;/code&gt; is a fun one because we use it all the time and most of the time it’s fine, until it’s not. Take this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;myNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;myNumberSet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&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;onClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;myNumberSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript is totally fine with this because the typing on &lt;code&gt;useState&lt;/code&gt; looks at the initial value, sees that it’s a &lt;code&gt;number&lt;/code&gt; and sets this type to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;myNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;myNumberSet&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So any number is going to be fine.&lt;/p&gt;

&lt;p&gt;The problem comes up when you have something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;myAccount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;myAccountSet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="nx"&gt;onAuthResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;myAccountSet&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;foo&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript has no idea that what you initially set to &lt;code&gt;null&lt;/code&gt; could potentially be an account record. So what you need to do is tell it that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IAccount&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;myAccount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;myAccountSet&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IAccount&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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="nx"&gt;onAuthResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;myAccountSet&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;foo&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now TypeScript understands that your &lt;code&gt;myAccount&lt;/code&gt; value can either be &lt;code&gt;null&lt;/code&gt; or an object that matches the typing of &lt;code&gt;IAccount&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A similar issue happens with arrays. Take this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;myNumbers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;myNumbersSet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;onClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;myNumbersSet&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript is going to give you a really odd error about trying to use a &lt;code&gt;number[]&lt;/code&gt; when a &lt;code&gt;never[]&lt;/code&gt; is expected. Which actually makes sense because, as far as TypeScript knows the only valid value is an empty array (i.e. &lt;code&gt;never[]&lt;/code&gt;). It has no idea you intend to store numbers in there.&lt;/p&gt;

&lt;p&gt;So the fix for this is to type it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;myNumbers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;myNumbersSet&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;myNumbersSet&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now TypeScript will be happy again because even an empty array is a valid type of &lt;code&gt;number[]&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  useEffect
&lt;/h3&gt;

&lt;p&gt;The great thing about &lt;code&gt;useEffect&lt;/code&gt; that that it doesn’t take any types. So if you are looking to make sure you are typing it correctly, fear not, you are.&lt;/p&gt;

&lt;p&gt;If you want to check that for yourself then right click on the word &lt;code&gt;useEffect&lt;/code&gt; in your VS Code and use the &lt;code&gt;Go to Type Definition&lt;/code&gt; command to go to where &lt;code&gt;useEffect&lt;/code&gt; is defined in the React source.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; takes two arguments, the first is a function with no parameters that either returns &lt;code&gt;void&lt;/code&gt;, or returns another function (the cleanup function), which takes no arguments and returns a &lt;code&gt;void&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;IMHO, using &lt;code&gt;Go to Type Definition&lt;/code&gt; should be your first stop any time you run into an issue in TypeScript.&lt;/p&gt;

&lt;h3&gt;
  
  
  useContext
&lt;/h3&gt;

&lt;p&gt;Getting &lt;code&gt;useContext&lt;/code&gt; typed properly really comes down to getting the &lt;code&gt;createContext&lt;/code&gt; call typed properly. For example, you might have something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which basically leaves TypeScript with no clue about what could potentially be in the context and so it leaves it at; the context must always contain &lt;code&gt;null&lt;/code&gt;. Which is probably not what you want.&lt;/p&gt;

&lt;p&gt;The easiest way to handle this would be, if you want either &lt;code&gt;null&lt;/code&gt; or some data, to define it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;IMyContextState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;userID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;MyContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IMyContextState&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which tells TypeScript that the context must either contain an object that matches &lt;code&gt;IMyContextState&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you have a default state it gets a lot easier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myDefaultState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;userID&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MyContextType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;myDefaultState&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;MyContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myDefaultState&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="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case we don’t need to tell TypeScript that the context has the types in &lt;code&gt;myDefaultState&lt;/code&gt; it already knows that, but we now export the schema of the default state as &lt;code&gt;MyContextType&lt;/code&gt;. So that we can then use it when we call &lt;code&gt;useContext&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MyContextType&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="s1"&gt;./store&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;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;MyContextType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The typing of &lt;code&gt;ctx&lt;/code&gt; is a bit of overkill in this case because &lt;code&gt;useContext&lt;/code&gt; already knows the types from &lt;code&gt;MyContext&lt;/code&gt; and you can just get away with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyContext&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./store&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;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  useReducer
&lt;/h3&gt;

&lt;p&gt;Typing &lt;code&gt;useReducer&lt;/code&gt; is a lot like typing Redux, so it’s a two-fer, if you get this right, you are that much closer to Redux typing. So &lt;code&gt;useReducer&lt;/code&gt; takes two things, the &lt;code&gt;reducer&lt;/code&gt; function and the initial state. Let’s start off with the initial state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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;Next we need some actions. Now in Javascript we wouldn’t type these at all but in TypeScript we can and we should type them, and that would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ACTIONTYPES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;increment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;decrement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;And then the reducer is going to look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;myReducer&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ACTIONTYPES&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="kd"&gt;const&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;dispatch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myReducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this will give you hinting on the state and also ensure that any call to dispatch will need to match one of the variants in &lt;code&gt;ACTIONTYPES&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  useRef
&lt;/h3&gt;

&lt;p&gt;Typing &lt;code&gt;useRef&lt;/code&gt;, particularly when it comes to use refs with DOM elements, which is a pretty common use case is straightforward. Let’s say you have something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;inputRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your code then the corresponding &lt;code&gt;useRef&lt;/code&gt; would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inputRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLInputElement&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And specifying the types isn’t 100% necessary here either. The only trick is to make sure you get the right type for the corresponding DOM element.&lt;/p&gt;

&lt;p&gt;If you are going to use a ref to hold data then you can do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;intervalRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are, for example, holding a reference to an interval.&lt;/p&gt;

&lt;h3&gt;
  
  
  useMemo
&lt;/h3&gt;

&lt;p&gt;The typing on &lt;code&gt;useMemo&lt;/code&gt; is all about what is produced by the factory function that you put in there. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;numbers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&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;filteredNums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;numbers&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;In this case the typing on &lt;code&gt;filteredNums&lt;/code&gt; is inferred by TypeScript to be &lt;code&gt;number[]&lt;/code&gt; because of the output of the factory function. If you wanted to type it you could do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredNums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;numbers&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;But you really don’t need to. TypeScript is very, very good at figuring out the return type of a function. In fact, if you want to you can use the &lt;code&gt;ReturnType&lt;/code&gt; utility type to get the return type from a function like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MyFunctionReturnType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;myFunction&lt;/span&gt;&lt;span class="o"&gt;&amp;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 more information on the &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html" rel="noopener noreferrer"&gt;amazing array of utility types on the TypeScript language site&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Video Version
&lt;/h3&gt;

&lt;p&gt;If you want to see an in-depth walk through of a lot of this information and much more check out the associated YouTube video:&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/zM_ZiSl2n2E"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;The more I work with TypeScript and React the more that I am convinced that it’s worth the investment. You get the benefits of hinting as you code. You are communicating your intent through the types. And you get the benefits of a type safety check at compile time.&lt;/p&gt;

&lt;p&gt;Hopefully this article will help you realize these benefits as you try out using TypeScript in your React projects and you learn to master the typing of your React hooks.&lt;/p&gt;




</description>
      <category>react</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Are Typescript Types Alone Enough Documentation?</title>
      <dc:creator>Jack Herrington</dc:creator>
      <pubDate>Mon, 25 Jan 2021 16:36:44 +0000</pubDate>
      <link>https://dev.to/jherr/are-typescript-types-alone-enough-documentation-47lj</link>
      <guid>https://dev.to/jherr/are-typescript-types-alone-enough-documentation-47lj</guid>
      <description>&lt;p&gt;Here is an interesting question; are the types in your Typescript project enough documentation, on their own, to allow someone to learn the library?&lt;/p&gt;

&lt;p&gt;That was the question I asked myself when I saw the Amazon had released a React UI library for AWS. They only released the code and the Typescript types. No documentation. No &lt;code&gt;storybook&lt;/code&gt; or &lt;code&gt;styleguidist&lt;/code&gt;. Just the code and the types.&lt;/p&gt;

&lt;p&gt;Now I love digging into UI libraries. And this was a fun challenge. Can I learn the library from just the source? So I started a Create React App using the &lt;code&gt;typescript&lt;/code&gt; template, then installed the &lt;code&gt;@awsui/components-react&lt;/code&gt; library and started my sleuthing.&lt;/p&gt;

&lt;p&gt;The first thing to realize is that VS Code loves Typescript, and in this journey it will be your invaluable partner. For example, you can right click on the import and ask for the definitions, as shown in the screenshot below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0Qq3oiqD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/519/1%2AFiUdcRZC7hCMve4mP-n6vg%402x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0Qq3oiqD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/519/1%2AFiUdcRZC7hCMve4mP-n6vg%402x.png" alt="" width="519" height="338"&gt;&lt;/a&gt;Using VS Code to navigate to the definitions&lt;/p&gt;

&lt;p&gt;And that takes you to the central definitions file that lists all the components and their properties.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6HlnjlGJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AOj2fExyG6UcSbtvZ8UAweQ%402x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6HlnjlGJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2AOj2fExyG6UcSbtvZ8UAweQ%402x.png" alt="" width="800" height="210"&gt;&lt;/a&gt;Just a few of the fascinating components in the AWS UI toolkit&lt;/p&gt;

&lt;p&gt;Jackpot! Now I know what’s in there. But how to use it?&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting The Layout Right
&lt;/h3&gt;

&lt;p&gt;Right away what captured my eye was &lt;code&gt;AppLayout&lt;/code&gt; because, really, there are two types of toys in a UI library; layout components and interactive components. And job number one is creating the layout, and job two is putting stuff in that layout.&lt;/p&gt;

&lt;p&gt;Naming is important, right? &lt;code&gt;AppLayout&lt;/code&gt;. Sounds good! I’m making an &lt;code&gt;App&lt;/code&gt;, check. And I need a &lt;code&gt;Layout&lt;/code&gt;, double check. &lt;code&gt;AppLayout&lt;/code&gt; it is! It also helped that it was alphabetical and in the A's.&lt;/p&gt;

&lt;p&gt;So I dropped an &lt;code&gt;AppLayout&lt;/code&gt; on the page and right away I got a three column layout with a collapsible &lt;code&gt;navigation&lt;/code&gt; panel to the left and a &lt;code&gt;tools&lt;/code&gt; panel to the right, with a &lt;code&gt;content&lt;/code&gt; section between. How did I know that? Because of the types!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zV9Ch4oE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2ABFQHu9woNB902kjGiigzvw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zV9Ch4oE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2ABFQHu9woNB902kjGiigzvw.png" alt="" width="800" height="549"&gt;&lt;/a&gt;The types for content, navigation and tools properties on the AppLayout component&lt;/p&gt;

&lt;p&gt;So this is not only telling me what sections are available, but also the kind of content they are expecting, in this case &lt;code&gt;ReactNode&lt;/code&gt; types which are, basically, anything renderable in React.&lt;/p&gt;

&lt;p&gt;I replaced the entire contents of the canned &lt;code&gt;App&lt;/code&gt; component with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppLayout&lt;/span&gt;
      &lt;span class="nx"&gt;navigation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;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;Navigation&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="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;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;Content&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="nx"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;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;Tools&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="o"&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;Then I ran &lt;code&gt;yarn start&lt;/code&gt; and right away I got a pretty decent looking responsive layout with three columns and collapsible sections. I was off to the races!&lt;/p&gt;

&lt;h3&gt;
  
  
  As Expected, With Exceptions
&lt;/h3&gt;

&lt;p&gt;I’m not one to just play with components, I want to build something real-ish. So I created a Pokemon filter application. Some things, like &lt;code&gt;Button&lt;/code&gt; were very straightforward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Say&lt;/span&gt; &lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This worked out of the box, but the button itself wasn’t very visually appealing by default. Once again, Typescript to the rescue!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pfh0947N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/841/1%2AEDMbdmxhDdNjAL5ox_0bwQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pfh0947N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/841/1%2AEDMbdmxhDdNjAL5ox_0bwQ.png" alt="" width="800" height="562"&gt;&lt;/a&gt;The potential variants of Button styling&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;Go To Definition&lt;/code&gt; in VSCode I was able to select a &lt;code&gt;Button&lt;/code&gt; component and drill until I found the &lt;code&gt;ButtonProps&lt;/code&gt; which showed me that there is a &lt;code&gt;variant&lt;/code&gt; prop that I could use to select different styles of button. I ended up going with &lt;code&gt;link&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another moment came when I was working with the &lt;code&gt;Input&lt;/code&gt; component, which, as you might guess is a text input. Everything was going great until I got to &lt;code&gt;onChange&lt;/code&gt; where the event structure was a little different from what we expect.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--stgvgOcw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1016/1%2AjEFFjuQWWl4RjVwlSFstEQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--stgvgOcw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1016/1%2AjEFFjuQWWl4RjVwlSFstEQ.png" alt="" width="800" height="237"&gt;&lt;/a&gt;Hinting on the event data from onChange&lt;/p&gt;

&lt;p&gt;In this case &lt;code&gt;event.target.value&lt;/code&gt; wasn’t there. Once again, VS Code to the rescue and I was able to find &lt;code&gt;event.detail.value&lt;/code&gt; was the droid I was looking for instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding a New Pattern
&lt;/h3&gt;

&lt;p&gt;Eventually I needed to put up a list of the Pokemon. I not only found a great &lt;code&gt;Cards&lt;/code&gt; component to do that, I also found a great way of defining generic React components. Check this out!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zRtdIUNW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A4p8k2Lojrj4jCV5E2LksZg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zRtdIUNW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/1024/1%2A4p8k2Lojrj4jCV5E2LksZg.png" alt="" width="800" height="609"&gt;&lt;/a&gt;Typescript generics for React components&lt;/p&gt;

&lt;p&gt;So you give &lt;code&gt;Cards&lt;/code&gt; an array of items and then you provide content functions that render the content for each item.&lt;/p&gt;

&lt;p&gt;Anyway, because Typescript, the AWS team defined &lt;code&gt;Card&lt;/code&gt; as a generic and when you pass an array in for that &lt;code&gt;items&lt;/code&gt; property Typescript automatically infers the type of the array and then applies it to the other parts of the property definitions as required. In your &lt;code&gt;content&lt;/code&gt; function you get type safety and hinting around the type from the array of items. And you don’t, as a consumer, need to do any additional work to make that happen. It just works, for free, just the way you’d expect it.&lt;/p&gt;

&lt;p&gt;Seeing this was the most exciting moment of discovery on this journey. For some reason or another I hadn’t really thought about using generics for React components. So it was a genuine “Ah ha!” moment that I got from &lt;strong&gt;reading the code&lt;/strong&gt;. This is not something I would have gotten from the documentation (most likely).&lt;/p&gt;

&lt;p&gt;In addition to generics, seeing this pattern where you give the component some data and a render function (which is a pattern throughout the toolkit) was great to see. I’d seen it before in toolkits like Apple’s iOS List component. But I’ve rarely seen it on the web and I think it’s a good architectural pattern that’s worthy of more extensive use.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Video Version&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you want to see my exploration of the AWS UI toolkit for yourself check out the YouTube version.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/VBbkLd-_dPU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The two big takeaways I learned from this sleuthing experience was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Learn To Read Code&lt;/strong&gt;  — Code is truth. And learning how to read someone else’s code can be a source of information, inspiration, education, all the good stuff. And what’s even better is that when you build that code reading muscle you can start to look at Github not just as a place to “grab code” but as the best code reading library the Universe has ever known.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typescript Is Documentation&lt;/strong&gt;  — Sure typing doesn’t answer all the questions. But it answers a lot of them very quickly, and it’s free. So the cost/benefit ratio is outstanding. &lt;strong&gt;Typescript is worth it, y’all.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bonus: Naming Is Really Important&lt;/strong&gt;  — I only scratched the surface on this library. There are tons of components. The only moments that I really struggled was with the naming on some of these components. For example; what’s a “Tile”? (Turns out it’s a radio button). Now that’s not really a fault of the folks at AWS. Naming is tough. But as frontend developers it would probably benefit us, at some point, to normalize what we name our UI elements, beyond Button.&lt;/li&gt;
&lt;/ul&gt;




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