<?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>Forem: Profy.dev</title>
    <description>The latest articles on Forem by Profy.dev (@profydev).</description>
    <link>https://forem.com/profydev</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%2Forganization%2Fprofile_image%2F3338%2F43691f8f-0edd-4c5e-bbc3-584d46d5f3c6.png</url>
      <title>Forem: Profy.dev</title>
      <link>https://forem.com/profydev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/profydev"/>
    <language>en</language>
    <item>
      <title>REST APIs - How To Connect Your React App Like The Pros (Incl Detailed Example)</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Fri, 07 Oct 2022 12:23:10 +0000</pubDate>
      <link>https://forem.com/profydev/rest-apis-how-to-connect-your-react-app-like-the-pros-incl-detailed-example-4hb8</link>
      <guid>https://forem.com/profydev/rest-apis-how-to-connect-your-react-app-like-the-pros-incl-detailed-example-4hb8</guid>
      <description>&lt;p&gt;Consuming REST APIs with React isn’t very difficult. It only takes a &lt;code&gt;useEffect&lt;/code&gt; plus a few lines of code and you have the data in your frontend.&lt;/p&gt;

&lt;p&gt;At least it seems like that at first.&lt;/p&gt;

&lt;p&gt;But once you start adding features to your data fetching logic you quickly end up with a big mess of entangled spaghetti code.&lt;/p&gt;

&lt;p&gt;Luckily there are a few libraries to our rescue (among them react-query). These not only make it really easy to fetch data but also deliver valuable and commonly used features right out of the box. &lt;/p&gt;

&lt;p&gt;On this page, we’ll use an example project to see how quickly a “simple” approach to data fetching using &lt;code&gt;useEffect&lt;/code&gt; can get out of hand. In contrast, we’ll see how easy it is to build advanced features using &lt;code&gt;react-query&lt;/code&gt; by building a snappy paginated list component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
The Project

&lt;ol&gt;
&lt;li&gt;React Frontend&lt;/li&gt;
&lt;li&gt;REST API&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

The “Simple” Approach With useEffect

&lt;ol&gt;
&lt;li&gt;The Code&lt;/li&gt;
&lt;li&gt;The Problems&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

The Effective Approach With react-query

&lt;ol&gt;
&lt;li&gt;The Advantages&lt;/li&gt;
&lt;li&gt;Setup&lt;/li&gt;
&lt;li&gt;A Simple Implementation&lt;/li&gt;
&lt;li&gt;Advanced Features For Free&lt;/li&gt;
&lt;li&gt;Custom Hook As Best Practice&lt;/li&gt;
&lt;li&gt;Usage With TypeScript&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

Advanced Example: A Paginated List Component With Great UX

&lt;ol&gt;
&lt;li&gt;Simple Pagination&lt;/li&gt;
&lt;li&gt;Prefetching The Next Page&lt;/li&gt;
&lt;li&gt;Reducing The Number Of Requests By Adjusting The Stale Time&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Summary&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Project
&lt;/h2&gt;

&lt;p&gt;Nobody wants to read through the setup of a new React app, I assume. So I prepared a realistic project for this article that shows a slightly more advanced use case for data fetching.&lt;/p&gt;

&lt;p&gt;It’s an error-tracking tool similar to Sentry that I created for the &lt;a href="https://profy.dev" rel="noopener noreferrer"&gt;React Job Simulator&lt;/a&gt;. It includes a React / Next.js frontend and a REST API which we will get our data from.&lt;/p&gt;

&lt;h3&gt;
  
  
  React Frontend
&lt;/h3&gt;

&lt;p&gt;The goal is to fetch data and render it in our frontend like this:&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%2Fmedia.graphassets.com%2FQeyfpdYQDCgLl8DEU4bG" 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%2Fmedia.graphassets.com%2FQeyfpdYQDCgLl8DEU4bG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that this list has several pages (note the “Previous” and “Next” buttons at the bottom). This is very common in real-world projects.&lt;/p&gt;

&lt;p&gt;But currently, we only see a single issue that is hard-coded in our frontend code.&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%2Fmedia.graphassets.com%2FrZxMZDfORA6TXvCld7fQ" 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%2Fmedia.graphassets.com%2FrZxMZDfORA6TXvCld7fQ"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code responsible for rendering the list looks like the following at the moment. The goal is to replace the hard-coded data with data fetched from 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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;IssueList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// hard-coded issues data&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;items&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mock-id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;6d5fff43-d691-445d-a41a-7d0c639080e6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mock Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This is hard-coded data that doesn't come from an API&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Some mock stack trace&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;numEvents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;105&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;numUsers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;56&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// hard-coded meta data used for pagination&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;hasNextPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;currentPage&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="na"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// state variable used for pagination&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;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPage&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="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;Container&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;Table&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;thead&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;HeaderRow&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;HeaderCell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Issue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/HeaderCell&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;HeaderCell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Level&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/HeaderCell&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;HeaderCell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Events&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/HeaderCell&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;HeaderCell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/HeaderCell&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;/HeaderRow&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;/thead&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;tbody&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;items&lt;/span&gt; &lt;span class="o"&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="nx"&gt;issue&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;IssueRow&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;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;issue&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/tbody&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;/Table&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;PaginationContainer&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;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;PaginationButton&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;setPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&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;Previous&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/PaginationButton&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;PaginationButton&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;setPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasNextPage&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;Next&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/PaginationButton&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PageInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PageNumber&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;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentPage&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;/PageNumber&amp;gt; of{" "&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PageNumber&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;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalPages&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;/PageNumber&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;/PageInfo&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;/PaginationContainer&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;/Container&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;h3&gt;
  
  
  REST API
&lt;/h3&gt;

&lt;p&gt;To get our data we’ll use the REST endpoint &lt;a href="https://prolog-api.profy.dev/issue" rel="noopener noreferrer"&gt;prolog-api.profy.dev/issue&lt;/a&gt; (click the link to see the JSON response). You can find more details about this REST API in &lt;a href="https://prolog-api.profy.dev/api" rel="noopener noreferrer"&gt;its Swagger API documentation&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;This is the response for the first page.&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"items"&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="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"c9613c41-32f0-435e-aef2-b17ce758431b"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"projectId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6d5fff43-d691-445d-a41a-7d0c639080e6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TypeError"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cannot read properties of undefined (reading 'length')"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"stack"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cannot read properties of undefined (reading 'length')&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at eval (webpack-internal:///./pages/index.tsx:37:7)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at invokePassiveEffectCreate (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:23482:20)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at HTMLUnknownElement.callCallback (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:3945:14)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at HTMLUnknownElement.sentryWrapped (webpack-internal:///./node_modules/@sentry/browser/esm/helpers.js:81:23)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at Object.invokeGuardedCallbackDev (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:3994:16)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at invokeGuardedCallback (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:4056:31)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at flushPassiveEffectsImpl (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:23569:9)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at unstable_runWithPriority (webpack-internal:///./node_modules/scheduler/cjs/scheduler.development.js:468:12)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at runWithPriority$1 (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:11276:10)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at flushPassiveEffects (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:23442:14)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at eval (webpack-internal:///./node_modules/react-dom/cjs/react-dom.development.js:23319:11)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at workLoop (webpack-internal:///./node_modules/scheduler/cjs/scheduler.development.js:417:34)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at flushWork (webpack-internal:///./node_modules/scheduler/cjs/scheduler.development.js:390:14)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    at MessagePort.performWorkUntilDeadline (webpack-internal:///./node_modules/scheduler/cjs/scheduler.development.js:157:27)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"resolved"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"numEvents"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;105&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"numUsers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;56&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="err"&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;"meta"&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;"currentPage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"totalItems"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"totalPages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hasPreviousPage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hasNextPage"&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="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;issue&lt;/code&gt; endpoint is a simple GET endpoint. But (as common in production APIs) this endpoint is paginated. That means that we don’t get all issues in a single request but only 10 at once (aka 10 per page). To get the next “page” of issues we simply append a query parameter like &lt;a href="https://prolog-api.profy.dev/issue?page=2" rel="noopener noreferrer"&gt;prolog-api.profy.dev/issue?page=2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The endpoint also returns a &lt;code&gt;meta&lt;/code&gt; object that contains information related to the pagination like the current page or the number of total pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  The “Simple” Approach With useEffect
&lt;/h2&gt;

&lt;p&gt;Let’s start with a “simple” approach that many beginner tutorials teach. We’ll see that it’s in fact very simple to get the data and render it in the UI. But as soon as we go into the nitty-gritty details things start to get complex.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Code
&lt;/h3&gt;

&lt;p&gt;Inside our component, we want to fetch the data during the initial render. With the &lt;code&gt;useEffect&lt;/code&gt; hook this is 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="nx"&gt;axios&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;axios&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;IssueList&lt;/span&gt;&lt;span class="p"&gt;()&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;axios&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://prolog-api.profy.dev/issue&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;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="c1"&gt;// empty dependency array means this runs only once (at least in production)&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;blockquote&gt;
&lt;p&gt;Note: We use &lt;a href="https://axios-http.com/docs/intro" rel="noopener noreferrer"&gt;axios&lt;/a&gt; here instead of the native &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" rel="noopener noreferrer"&gt;fetch API&lt;/a&gt; since it is &lt;a href="https://blog.logrocket.com/axios-vs-fetch-best-http-requests/" rel="noopener noreferrer"&gt;simpler to use and has some additional features&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When we refresh the app we now see the data logged in the console of our browser:&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%2Fmedia.graphassets.com%2FfR0vDWfTSKiNN8N4blM5" 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%2Fmedia.graphassets.com%2FfR0vDWfTSKiNN8N4blM5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we have to save the data in a state variable to render it in the UI.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;IssueList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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;axios&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://prolog-api.profy.dev/issue&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;response&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;setItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voila, we see the data in our app.&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%2Fmedia.graphassets.com%2FUldpyu5CRVMzMZdqugOd" 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%2Fmedia.graphassets.com%2FUldpyu5CRVMzMZdqugOd"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Easy enough, isn’t it?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problems
&lt;/h3&gt;

&lt;p&gt;Yes, just fetching data like that is easy. But in a production application, we can’t just leave it there. What if we wanted to handle loading and error 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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;IssueList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="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="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="nx"&gt;setError&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="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="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;axios&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://prolog-api.profy.dev/issue?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&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;setItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&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;items&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&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="nf"&gt;setError&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="k"&gt;finally&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;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="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="k"&gt;if &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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;An&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;occured&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if we wanted to add a route parameter for pagination and cancel previous requests when the page changes?&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;IssueList&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;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPage&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="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="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="nx"&gt;setError&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="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="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;abortController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;axios&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://prolog-api.profy.dev/issue?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;abortController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&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;setItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&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;items&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&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="c1"&gt;// this is easily missed&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;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;canceled&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;setError&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;span class="k"&gt;finally&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;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="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;abortController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="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="k"&gt;if &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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;An&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;occured&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if we wanted to add other features that are often a requirement in real-world applications? Like&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- retry requests when an error occurs
- pre-fetch data for the next page to improve UX
- refresh stale data after a while
- cache response data.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You get where this is going. The initially simple-looking code can quickly become a nightmare of entangled spaghetti full of bugs. Believe me, in a previous job a few years ago we went down this road… and it wasn’t pretty.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/react-rest-api#around-react-signup" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhfnci4btbcu10daw938.png" alt="Around React Email Course Signup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Effective Approach With react-query
&lt;/h2&gt;

&lt;p&gt;Luckily since a few years, we have libraries that abstract a lot of common use cases of data fetching. &lt;a href="https://profy.dev/article/react-tech-stack#react-query-or-apollo-as-popular-react-fetching-library" rel="noopener noreferrer"&gt;Popular examples are react-query, Redux Toolkit Query, or Apollo.&lt;/a&gt; react-query is one of the most widespread and versatile ones so we use it for this tutorial.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Advantages
&lt;/h3&gt;

&lt;p&gt;To get an overview of all the advantages it is a good idea to have a look at the &lt;a href="https://tanstack.com/query" rel="noopener noreferrer"&gt;react-query documentation&lt;/a&gt;. But I think this screenshot says it all.&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%2Fmedia.graphassets.com%2FsxC5JAhSUiibFXfuMcGC" 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%2Fmedia.graphassets.com%2FsxC5JAhSUiibFXfuMcGC"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;To use &lt;code&gt;react-query&lt;/code&gt; we need to wrap our app component with a &lt;code&gt;QueryClientProvider&lt;/code&gt;. This is common practice that you probably know from other libraries as well.&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;QueryClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;QueryClientProvider&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ReactQueryDevtools&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-devtools&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;queryClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;QueryClient&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;MyApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&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;QueryClientProvider&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&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;ReactQueryDevtools&lt;/span&gt; &lt;span class="nx"&gt;initialIsOpen&lt;/span&gt;&lt;span class="o"&gt;=&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="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;/QueryClientProvider&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;Additionally, we added the dev tools that come with &lt;code&gt;react-query&lt;/code&gt;. We will talk about this further down the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Simple Implementation
&lt;/h3&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;axios&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;axios&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;IssueList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isError&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;=&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;issues&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;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://prolog-api.profy.dev/issue&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;An&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;occured&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="nx"&gt;message&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="c1"&gt;// data is here the response object returned by axios&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;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&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;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These simple three lines of code give us already a loading and error state. &lt;/p&gt;

&lt;p&gt;The first parameter &lt;code&gt;["issues"]&lt;/code&gt; that we pass to &lt;code&gt;useQuery&lt;/code&gt; is used as a unique identifier for the data stored in the cache. The second parameter is the callback that connects to the API (the same axios call that we used in the &lt;code&gt;useEffect&lt;/code&gt;). Optionally we can pass a third parameter with config options.&lt;/p&gt;

&lt;p&gt;You can see that &lt;code&gt;useQuery&lt;/code&gt; doesn’t actually fetch the data itself but is more like a wrapper around the data-fetching callback that adds additional functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced Features For Free
&lt;/h3&gt;

&lt;p&gt;We saw at first glance that the loading and error states are supported out of the box. But under the hood, we also get a few really handy advanced features for free. Here are a few examples:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. A request cache that automatically updates in the background&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this video, you can see that a request is sent on the initial page load (the loading screen is shown). But when we navigate to another page and back we don’t see the loading screen anymore. The data is immediately there because it was cached.&lt;/p&gt;

&lt;p&gt;This isn’t all though. In the network tab at the bottom, you can see that a request is sent in the background. The cache is automatically updated with the newest server data.&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%2Fmedia.graphassets.com%2Fpr5q5TZNT2eQnVl0H2Du" 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%2Fmedia.graphassets.com%2Fpr5q5TZNT2eQnVl0H2Du"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Automatic updates of stale data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The cache is not only updated when we navigate back and forth inside the application. When the user switches to another tab and comes back to our app the data is by default updated in the background as well.&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%2Fmedia.graphassets.com%2FoObNm12iTKGwj3mxjyKM" 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%2Fmedia.graphassets.com%2FoObNm12iTKGwj3mxjyKM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Dev tools&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You may have seen the “flower” icon at the bottom left of the page? That’s the button to open the dedicated &lt;code&gt;react-query&lt;/code&gt; dev tools. You can see exactly what kind of requests have been sent, what’s in the cache, and the data plus additional information for each request. &lt;/p&gt;

&lt;p&gt;Very handy for debugging.&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%2Fmedia.graphassets.com%2FDUNFJ3Ske72DmxTP4Ktg" 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%2Fmedia.graphassets.com%2FDUNFJ3Ske72DmxTP4Ktg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Hook As Best Practice
&lt;/h3&gt;

&lt;p&gt;Since data fetching logic is often shared between multiple components it’s best practice &lt;a href="https://tkdodo.eu/blog/practical-react-query#create-custom-hooks" rel="noopener noreferrer"&gt;to extract custom hooks for each endpoint&lt;/a&gt;.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useIssues&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="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;issues&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;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://prolog-api.profy.dev/issue`&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;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use this hook in our component.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;IssueList&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;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPage&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;issuesPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useIssues&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;issuesPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issuesPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;An&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;occured&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;issuesPage&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="nx"&gt;message&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;issuesPage&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="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;Note that we have separated the fetching logic from the component now. In the previous simple example, the component used the response object from &lt;code&gt;axios&lt;/code&gt; directly. Now we can easily encapsulate this in our custom hook. This can be beneficial, for example, if we want to replace &lt;code&gt;axios&lt;/code&gt; with something else at some point.&lt;/p&gt;

&lt;p&gt;To further improve our custom hook it’s common to extract the data fetching callback into its own function.&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getIssues&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://prolog-api.profy.dev/issue&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useIssues&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;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;issues&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;getIssues&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 &lt;code&gt;axios&lt;/code&gt; is further isolated and the &lt;code&gt;getIssues&lt;/code&gt; function is responsible for handling the response data. Additionally, we can reuse the &lt;code&gt;getIssues&lt;/code&gt; function in other parts of our app (e.g. the server for server-side rendering).&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage With TypeScript
&lt;/h3&gt;

&lt;p&gt;For type safety and improved developer experience, it’s easy to use TypeScript with &lt;code&gt;react-query&lt;/code&gt;. Simply pass the type of the expected response data plus an error type to the &lt;code&gt;useQuery&lt;/code&gt; generic.&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;useQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useQueryClient&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;import&lt;/span&gt; &lt;span class="nx"&gt;axios&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;axios&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IssuePage&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;./types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://prolog-api.profy.dev/issue?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IssuePage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;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;issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;getIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;query&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 types in our case might 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;PageMeta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;currentPage&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="nl"&gt;limit&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="nl"&gt;totalItems&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="nl"&gt;totalPages&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="nl"&gt;hasPreviousPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;hasNextPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;IssueLevel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;info&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;warning&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;warning&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&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;type&lt;/span&gt; &lt;span class="nx"&gt;Issue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;projectId&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="nl"&gt;name&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="nl"&gt;message&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="nl"&gt;stack&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="nl"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IssueLevel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;numEvents&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;IssuePage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nl"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PageMeta&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 we not only have advanced errors and warnings in our IDE. We don’t even have to remember the data structure of our API data. The IDE’s autocomplete feature (here VS Code) takes care of that.&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%2Fmedia.graphassets.com%2FZVZ7UmeGRxKNIeDOzSd9" 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%2Fmedia.graphassets.com%2FZVZ7UmeGRxKNIeDOzSd9"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/react-rest-api#around-react-signup" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhfnci4btbcu10daw938.png" alt="Around React Email Course Signup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Example: A Paginated List Component With Great UX
&lt;/h2&gt;

&lt;p&gt;Great, we saw a simple example of how to make a request to our REST API. We also already saw some of the hidden powers that come with &lt;code&gt;react-query&lt;/code&gt; out of the box.&lt;/p&gt;

&lt;p&gt;Now it’s time for a slightly more advanced example. We’ll implement the pagination for our issue list. At the surface, this only means adding a query parameter to the request URL. But as we’ll see in a bit there are some UX hick-ups that we’ll run into. &lt;/p&gt;

&lt;p&gt;It’s magic how easily those are fixed just by adjusting a few &lt;code&gt;react-query&lt;/code&gt; options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple Pagination
&lt;/h3&gt;

&lt;p&gt;Let’s start by adding pagination. In our &lt;code&gt;useIssues&lt;/code&gt; hook we can simply add a parameter and append it to the URL.&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;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&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;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://prolog-api.profy.dev/issue?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&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;issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we also added the &lt;code&gt;page&lt;/code&gt; parameter to the cache identifier of &lt;code&gt;useQuery&lt;/code&gt;. You can compare it to the dependency array of the &lt;code&gt;useEffect&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;In our component, we can simply pass the &lt;code&gt;page&lt;/code&gt; state variable to the &lt;code&gt;useIssues&lt;/code&gt; hook and connect it to the pagination buttons.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;IssueList&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;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPage&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;issuesPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issuesPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issuesPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;An&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;occured&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;issuesPage&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="nx"&gt;message&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="c1"&gt;// we use the meta data returned in the response to disable&lt;/span&gt;
  &lt;span class="c1"&gt;// the "Next" button below&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;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;issuesPage&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="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;Container&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;Table&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;thead&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;HeaderRow&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;HeaderCell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Issue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/HeaderCell&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;HeaderCell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Level&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/HeaderCell&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;HeaderCell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Events&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/HeaderCell&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;HeaderCell&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/HeaderCell&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;/HeaderRow&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;/thead&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;tbody&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;items&lt;/span&gt; &lt;span class="o"&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="nx"&gt;issue&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;IssueRow&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;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;issue&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/tbody&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;/Table&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;PaginationContainer&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;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;PaginationButton&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;setPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&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;Previous&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/PaginationButton&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;PaginationButton&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;setPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
            &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasNextPage&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;Next&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/PaginationButton&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PageInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PageNumber&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;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentPage&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;/PageNumber&amp;gt; of{" "&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PageNumber&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;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalPages&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;/PageNumber&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;/PageInfo&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;/PaginationContainer&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;/Container&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 pagination works already well. When clicking on the buttons at the bottom able to see the different pages of issues as expected. As a bonus, thanks to the automatic caching the user doesn’t even see a loading screen when navigating to a previous page.&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%2Fmedia.graphassets.com%2F7ArESgQlTKi33wAu6O52" 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%2Fmedia.graphassets.com%2F7ArESgQlTKi33wAu6O52"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But as you can see the loading state that is shown when clicking on the “Next” button is pretty annoying. The table disappears completely until the new data arrives.&lt;/p&gt;

&lt;p&gt;It would be great if we could show the old data until the next page is loaded. And no surprise, this is very simple: we just need to add an option to &lt;code&gt;useQuery&lt;/code&gt;.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&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;issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;keepPreviousData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The loading state is gone! The table doesn’t disappear anymore.&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%2Fmedia.graphassets.com%2FIPt1WDATaONIRTT7lS6p" 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%2Fmedia.graphassets.com%2FIPt1WDATaONIRTT7lS6p"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This looks already a lot nicer. But the drawback is the delay between the button click and the next page being rendered. Depending on how fast the request resolves the user might not understand that the button has any effect and fall into “click rage”.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prefetching The Next Page
&lt;/h3&gt;

&lt;p&gt;But of course, &lt;code&gt;react-query&lt;/code&gt; is there to the rescue. &lt;a href="https://tanstack.com/query/v4/docs/guides/prefetching" rel="noopener noreferrer"&gt;The docs have a section about prefetching data&lt;/a&gt; so that the user doesn’t have to wait. Here is the code from the docs:&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;prefetchTodos&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="c1"&gt;// The results of this query will be cached like a normal query&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prefetchQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;fetchTodos&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;Even better, the docs (can’t praise them enough) provide examples for common use cases. Among them &lt;a href="https://tanstack.com/query/v4/docs/examples/react/pagination" rel="noopener noreferrer"&gt;an example implementation for pagination that includes prefetching the next page&lt;/a&gt;. Let’s adapt that example to our application:&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;axios&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;axios&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="nx"&gt;useQueryClient&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&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;issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;keepPreviousData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Prefetch the next page!&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQueryClient&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasNextPage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;queryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prefetchQuery&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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;getIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;queryClient&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;query&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 makes paginating basically instantaneous. There’s no delay for the user (as long as the prefetch request has been resolved obviously).&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%2Fmedia.graphassets.com%2FvTwZewBhRF6w4FH8tZgQ" 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%2Fmedia.graphassets.com%2FvTwZewBhRF6w4FH8tZgQ"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you look at the network requests at the bottom you can see how the next page is already loaded upfront.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reducing The Number Of Requests By Adjusting The Stale Time
&lt;/h3&gt;

&lt;p&gt;There’s a last small issue though: when clicking the “Next” button there are two requests. On the initial page load there are two requests as expected (page 1 and 2). But when we click on the “Next” button there are again two requests (page 2 and 3).&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%2Fmedia.graphassets.com%2FSmELAAuASRKPxad814K9" 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%2Fmedia.graphassets.com%2FSmELAAuASRKPxad814K9"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reason is that &lt;code&gt;react-query&lt;/code&gt; refetches “stale” data automatically. But for our kind of app, the data doesn’t go stale that quickly so the duplicate request for page 2 isn’t necessary. The additional requests may increase our server costs so we can as well get rid of them.&lt;/p&gt;

&lt;p&gt;The solution is simple: we add another option called &lt;code&gt;staleTime&lt;/code&gt; that we pass to &lt;code&gt;useQuery&lt;/code&gt;.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&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;issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getIssues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;keepPreviousData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// data is considered stale after one minute&lt;/span&gt;
    &lt;span class="na"&gt;staleTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60000&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;Now we only see one request for the second page. We got rid of the unnecessary request.&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%2Fmedia.graphassets.com%2FujC6fJyQIK4VEzdtBWJs" 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%2Fmedia.graphassets.com%2FujC6fJyQIK4VEzdtBWJs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;While &lt;code&gt;useEffect&lt;/code&gt; combined with &lt;code&gt;fetch&lt;/code&gt; or &lt;code&gt;axios&lt;/code&gt; seems like a simple solution at first you risk ending up with a whole bunch of unmaintainable spaghetti code.&lt;/p&gt;

&lt;p&gt;Modern React projects use libraries to outsource the complexities of common use cases in data fetching. &lt;code&gt;react-query&lt;/code&gt; is currently one of the most popular data-fetching libraries. And you have seen its power.&lt;/p&gt;

&lt;p&gt;With only a few lines of code and a few config options, we were able to create a snappy paginated list with fairly good UX.&lt;/p&gt;

&lt;p&gt;Still, we’ve seen only a fraction of what’s possible with &lt;code&gt;react-query&lt;/code&gt;. &lt;a href="https://tanstack.com/query" rel="noopener noreferrer"&gt;Check out the awesome docs for many more features.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/react-rest-api#around-react-signup" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhfnci4btbcu10daw938.png" alt="Around React Email Course Signup"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How To Approach A React Pair Programming Interview (Not Only The Tech Skills Count)</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Fri, 30 Sep 2022 11:35:01 +0000</pubDate>
      <link>https://forem.com/profydev/how-to-approach-a-react-pair-programming-interview-not-only-the-tech-skills-count-3jk6</link>
      <guid>https://forem.com/profydev/how-to-approach-a-react-pair-programming-interview-not-only-the-tech-skills-count-3jk6</guid>
      <description>&lt;p&gt;You’re invited to a React interview with a live coding session? Your first reaction was 🎉 and your second “OMG, what am I going to do? 🤯”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pair programming sessions during an interview are really scary.&lt;/strong&gt; Much more scary than take-home assignments. Especially if you’re applying for your first React job. There’s a much more experienced and professional developer who watches you writing code? And asks questions?&lt;/p&gt;

&lt;p&gt;But hey, when life gives you lemons make lemonade. &lt;strong&gt;As intimidating as they are live coding sessions can be a real opportunity.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;In contrast to take-home challenges, they don’t take that much of your time and you can show off a much broader skill set:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Communication skills.
- Thought process.
- Personality.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;And these can help you land the job even if you didn’t ace the challenge from a technical perspective.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As you will see on this page, you don’t need to be a 10x developer to ace a pair programming interview. &lt;strong&gt;You don’t even have to finish the challenge.&lt;/strong&gt; So don’t worry too much about the coding part itself. &lt;strong&gt;Instead, show the interviewer that you have a structured thought and problem-solving process.&lt;/strong&gt; Your chances of getting to the next stage will skyrocket.&lt;/p&gt;

&lt;p&gt;Read on to learn how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Soft Skills Are Important&lt;/li&gt;
&lt;li&gt;
How To Approach A Pair Programming Interview

&lt;ol&gt;
&lt;li&gt;Clarification&lt;/li&gt;
&lt;li&gt;Planning&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Transparent Communication When The Time Runs Out&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

How To Practice For A Pair Programming Interview

&lt;ol&gt;
&lt;li&gt;Tech Skills&lt;/li&gt;
&lt;li&gt;Common Tasks&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  Soft Skills Are Important
&lt;/h2&gt;

&lt;p&gt;Who would you select for a job?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A developer who dives head-first into the challenge, cranking out code like crazy, but at the same time runs in the wrong direction because they misunderstood the task.&lt;/li&gt;
&lt;li&gt;A developer who writes pretty good code but comes off as arrogant and gets defensive when you ask questions.&lt;/li&gt;
&lt;li&gt;A developer who takes a bit longer to write code, makes mistakes, or doesn’t finish the task in time. But they ask questions, make sure they understand the task, share their thought process along the way, and are receptive to feedback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don’t get me wrong, the ideal candidate has both strong technical and strong soft skills. But even if you’re not a 10x developer from a technical perspective you can make a lot of ground with your soft skills&lt;/p&gt;

&lt;p&gt;Just how to do so?&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Approach A Pair Programming Interview
&lt;/h2&gt;

&lt;p&gt;In this section, &lt;strong&gt;you’ll learn about a little framework&lt;/strong&gt; that you can use when you go into a pair programming interview. It consists of four phases and is based on how work in a real-world developer team happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clarification.&lt;/li&gt;
&lt;li&gt;Planning.&lt;/li&gt;
&lt;li&gt;Implementation.&lt;/li&gt;
&lt;li&gt;Transparent communication (when the time runs out).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you walk through these steps in a pair programming session you’ll signal a certain level of seniority in your thought process that many Junior developers lack.&lt;/strong&gt; As you’ll see in a bit things that might look like annoyances or failures at first glance (e.g. asking questions or running out of time) are in fact opportunities to prove your professionalism and communication skills.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clarification
&lt;/h3&gt;

&lt;p&gt;A mistake that many developers (especially inexperienced ones) make, is to read the task once and dive head-first into the code. But to the interviewer, this can be a sign of Junior’s mindset. Such a rushed approach is a sign that on the job you might head in the wrong direction and waste lots of valuable time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So before you start coding you should clarify the requirements.&lt;/strong&gt; Read the assignment again and ask the interviewer if you have any questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Even if you think everything is clear there might be hidden assumptions on both sides.&lt;/strong&gt; To flush those out you can repeat the task step by step in your own words. Like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"I just want to make sure that I get everything right. I have to do ... Is that right?".&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This might feel like you’re annoying the interviewer. But it’s an essential process in real-world teams that prevents developers from wasting lots of time building features that don’t work as intended.&lt;/p&gt;

&lt;h3&gt;
  
  
  Planning
&lt;/h3&gt;

&lt;p&gt;When the requirements are clear you can make a rough plan. &lt;strong&gt;Tell the interviewer how you would approach the problem.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, a common task is to fetch data from an API and render it. You could start by checking the response of the API in the browser (if it’s a simple GET request). &lt;strong&gt;Then you’d say:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"There are two options to fetch the data: I could use a&lt;/em&gt; &lt;em&gt;&lt;code&gt;useEffect&lt;/code&gt;&lt;/em&gt; &lt;em&gt;and implement the API call there. But usually, I'd use a library like&lt;/em&gt; &lt;em&gt;&lt;code&gt;react-query&lt;/code&gt;&lt;/em&gt;&lt;em&gt;. It’s very useful because it helps to handle a lot of overhead related to data fetching like loading state, error handling, caching, and so on. Then depending on the data structure I'd iterate over the array and render it in a component.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This again helps to flush out hidden assumptions and misunderstandings. On top of that, coming up with different options and weighing them against each other is again a sign of seniority.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: even if you haven’t worked with &lt;code&gt;react-query&lt;/code&gt; or similar libraries before you can still say that it’s a popular choice but you don’t have experience with it yet.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Now it’s time to write the code. Obviously, it’s good if you practiced similar tasks before (more on that in a bit). A pair programming interview is a very stressful situation already. And having the practice and ideally, a bit of muscle memory will help you stay calm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;While you’re coding it’s a good idea to talk out loud.&lt;/strong&gt; Explain what you just did and what you’re trying to achieve next. This shows your communication skills and highlights your thought process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When you get stuck or don’t remember something you’re often allowed to use Google. You can also ask your interviewer for help.&lt;/strong&gt; This is not a sign of weakness. It happens to everyone (especially in a stressful situation like this). And on the job, a common mistake by Junior developers is to not ask for help when they’re stuck. They often rather dig down a rabbit hole and waste time going in the wrong direction when the solution is indeed simple.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finally, if you know how to write tests definitely go for it.&lt;/strong&gt; You don’t need to test everything or use a TDD approach. Just one or two tests will show the interviewer that you are comfortable with this. You’ll appear much more professional. It might be a good idea to ask upfront though:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"I'd usually write a test for this component. But since the time is limited should I write one now?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not many candidates write tests in coding challenges. So this is a great way to stand out.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Transparent Communication When The Time Runs Out
&lt;/h3&gt;

&lt;p&gt;From my experience, it’s often not that important to finish all the assignments in time. Especially if you take the time to clarify everything, talk the interviewer through your code, and write some tests, &lt;strong&gt;there’s a good chance that you don’t finish everything&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let me share my personal way story: I was on a pair-programming interview. React hooks were still pretty new and I made the mistake of using &lt;code&gt;useEffect&lt;/code&gt; to fetch data from an API even though I wasn’t very familiar with it. In this stressful situation, I failed to finish the task. But the interviewer appreciated that I talked him through my attempts and I passed the interview anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you realize that you’re running out of time upfront it’s a good idea to be transparent:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Hey look, it's obvious that I won't complete the task in time. I still have to style this component and make the button callback work. Is there anything you want me to focus on?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Running out of time (aka underestimating tasks) is very common in real-world projects.&lt;/strong&gt; The most important thing is that developers openly communicate this to their managers. This allows the team to cut scope and at least ship something.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/coding-challenges-signup" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kxabcnxtn672d02oifq.png" alt="Get access to the React Coding Challenges"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How To Practice For A Pair Programming Interview
&lt;/h2&gt;

&lt;p&gt;Now that we talked about the importance of soft skills let’s move on to the technical part. Obviously, your tech skills are very important. Displaying a severe lack of React knowledge will likely cost you the job opportunity.&lt;/p&gt;

&lt;p&gt;And, as always, practice is key.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tech Skills
&lt;/h3&gt;

&lt;p&gt;Commonly tested technical skills are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;general rendering logic&lt;/strong&gt;: e.g. functional components, rendering JSX&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;state management&lt;/strong&gt;: e.g. local state with &lt;code&gt;useState&lt;/code&gt;, global or shared state with Context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;connecting to an API&lt;/strong&gt;: e.g. with &lt;code&gt;useEffect&lt;/code&gt; or a library like &lt;code&gt;react-query&lt;/code&gt;, handling loading and error state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;debugging&lt;/strong&gt;: navigating in and understanding an existing codebase, using debugging tools like Chrome dev tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;styling (not to forget)&lt;/strong&gt;: common CSS features like flexbox.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, you’re tested if you can write React components, handle (simple) real-world scenarios like data fetching, and work with CSS. &lt;/p&gt;

&lt;h3&gt;
  
  
  Common Tasks
&lt;/h3&gt;

&lt;p&gt;Interview challenges mostly aren’t too hard. At least if you would work on them in your usual environment. But in a stressful situation like a pair-programming interview, even simple tasks can turn very difficult.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So it can be helpful to know about common challenges and practice them upfront.&lt;/strong&gt; This way you will have a general solution in mind already (and maybe even some pitfalls that you can discuss upfront).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here are a few challenges&lt;/strong&gt; that are common from my experience and what I read in different communities: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building a dynamic feature: e.g. a form, a modal that opens via a button.&lt;/li&gt;
&lt;li&gt;Fetching and rendering data (from an API): e.g. a list of products and rendering them into a list or grid.&lt;/li&gt;
&lt;li&gt;Fixing bugs in a small project.&lt;/li&gt;
&lt;li&gt;Implementing a simple design.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these challenges test a variety of skills like CSS, state management, common JS array functions, API connections, and debugging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;While you practice these tasks don’t forget to practice the soft skills as well.&lt;/strong&gt; Talk out loud while you’re coding and apply the framework in the previous section (clarification, planning, implementation, transparent communication when the time runs out).&lt;/p&gt;

&lt;p&gt;I prepared a few &lt;a href="https://profy.dev/article/react-coding-challenges" rel="noopener noreferrer"&gt;React coding challenges&lt;/a&gt; that you can use for your interview preparation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Styling a header based on designs.&lt;/li&gt;
&lt;li&gt;Building a modal component that opens when a button is clicked.&lt;/li&gt;
&lt;li&gt;Fetching data from an API and rendering it.&lt;/li&gt;
&lt;li&gt;Fixing a bug in an existing codebase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://profy.dev/coding-challenges-signup" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kxabcnxtn672d02oifq.png" alt="Get access to the React Coding Challenges"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>career</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Testing React Apps With Cypress: An In-Depth Guide For Beginners</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Fri, 23 Sep 2022 11:30:40 +0000</pubDate>
      <link>https://forem.com/profydev/how-to-start-testing-react-apps-and-why-i-recommend-cypress-to-beginners-5el5</link>
      <guid>https://forem.com/profydev/how-to-start-testing-react-apps-and-why-i-recommend-cypress-to-beginners-5el5</guid>
      <description>&lt;p&gt;You know that you should write tests for your React applications.&lt;/p&gt;

&lt;p&gt;But reality shows that most Junior developers never have written a test. And to be honest, it doesn’t feel easy to start. You have to decide between a gazillion tools. &lt;strong&gt;Writing tests feels very different than writing your normal frontend code.&lt;/strong&gt; It’s awkward. And frustrating. Strange errors everywhere that you don’t know how to debug.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But once you get used to it you won’t wanna miss it.&lt;/strong&gt; You’ll feel much safer because code changes won’t break your app. No need for endless manual tests anymore. Not only that: Writing tests is best practice in many companies and &lt;a href="https://profy.dev/article/react-projects-for-your-portfolio#application-logic" rel="noopener noreferrer"&gt;lets you stand out as a candidate if you’re looking for your first developer job&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And turns out, it doesn’t have to be that hard. If you pick the right tools to start with and get a bit of guidance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On this page, you can find exactly that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We cover why Cypress is a great tool (especially for developers who are new to testing).&lt;/li&gt;
&lt;li&gt;We  start by writing a few simple UI tests.&lt;/li&gt;
&lt;li&gt;We move on to more complex tests involving data from API requests.&lt;/li&gt;
&lt;li&gt;Finally we learn how to debug our way through problems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But hold on. &lt;strong&gt;This is not a theoretical lesson&lt;/strong&gt; where you simply lean back and enjoy the content. I prepared a project that you can use to follow along. It’s a Next.js app that needs some testing love. We’ll write a few tests together but in the end, I’ll leave a few test cases for you to implement on your own.&lt;/p&gt;

&lt;p&gt;The goal is that you leave this tutorial with the skills to start testing your own applications. This is your chance to get hands-on testing experience! I hope you’re thrilled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/cypress-react#nl-5776319l5j5l8" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa99gx51fy7d2p5re1chn.png" alt="Click here to get the source code for this tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
Introduction

&lt;ol&gt;
&lt;li&gt;Why Cypress&lt;/li&gt;
&lt;li&gt;The Project Used In This Tutorial&lt;/li&gt;
&lt;li&gt;What To Test&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

Testing Navigation Links

&lt;ol&gt;
&lt;li&gt;Opening A URL With Cypress&lt;/li&gt;
&lt;li&gt;Accessing An Element Globally&lt;/li&gt;
&lt;li&gt;Switching Viewports&lt;/li&gt;
&lt;li&gt;Accessing A Specific Element By Text&lt;/li&gt;
&lt;li&gt;Interacting With Elements - Clicking&lt;/li&gt;
&lt;li&gt;Cypress Helps With Debugging&lt;/li&gt;
&lt;li&gt;Accessing The URL&lt;/li&gt;
&lt;li&gt;Exercise&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

Testing That The Navigation Is Collapsible

&lt;ol&gt;
&lt;li&gt;Clicking A Button&lt;/li&gt;
&lt;li&gt;What To Test&lt;/li&gt;
&lt;li&gt;Testing The Links&lt;/li&gt;
&lt;li&gt;Testing That Elements Are Hidden&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

Testing Pages With API Requests

&lt;ol&gt;
&lt;li&gt;What To Test&lt;/li&gt;
&lt;li&gt;Accessing Elements Within A Parent&lt;/li&gt;
&lt;li&gt;Iterating Over A List Of Elements&lt;/li&gt;
&lt;li&gt;Detour: Different Types Of Testing&lt;/li&gt;
&lt;li&gt;Mocking Requests/Responses With Cypress&lt;/li&gt;
&lt;li&gt;Asserting Against The Mock Data&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

Debugging Broken Tests

&lt;ol&gt;
&lt;li&gt;Using Chrome Dev Tools&lt;/li&gt;
&lt;li&gt;Setting Breakpoints&lt;/li&gt;
&lt;li&gt;Inpsecting Variables&lt;/li&gt;
&lt;li&gt;Inspecting DOM Elements&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Your Turn - More Exercises&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Cypress
&lt;/h3&gt;

&lt;p&gt;As with everything JavaScript, there are tons of testing tools in the React and web dev ecosystem. Some are outdated (like Enzyme). Some are super popular but somewhat hard on beginners (like React Testing Library). And &lt;strong&gt;one testing tool is popular in real-world projects AND has a relatively low learning curve&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cypress&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The big advantage and reason why I recommend it to beginners is the level of visual feedback and interactivity.&lt;/p&gt;

&lt;p&gt;The problem with other testing frameworks like RTL is that&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Writing tests feels different from your usual frontend code.&lt;/li&gt;
&lt;li&gt;All the output is in the terminal while you’re used to looking at the browser for feedback.&lt;/li&gt;
&lt;li&gt;The debugging experience is vastly different. More like debugging Node.js servers than React apps.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;With Cypress, you only have the first point.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once you get used to writing tests you can transfer this knowledge to other frameworks like RTL and get comfortable with the debugging experience there. And that’s surely a good idea since most tests are likely written with React Testing Library nowadays.&lt;/p&gt;

&lt;p&gt;But one step at a time. &lt;strong&gt;Let me show you why Cypress is so powerful.&lt;/strong&gt; On your local machine, it has a separate UI where all the tests are run. Next to a browser window where you can watch your tests step by step! &lt;/p&gt;

&lt;p&gt;You can click on each step of the tests and get some additional information. You can even open the Chrome dev tools in the browser, read the console output, inspect elements, and use the debugger.&lt;/p&gt;

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

&lt;p&gt;I hope the advantages are clear. You’re likely used to a lot of this stuff already. So it’s mostly Cypress and its API that you have to get used to. On top of that &lt;a href="https://docs.cypress.io/guides/getting-started/installing-cypress" rel="noopener noreferrer"&gt;Cypress is super easy to set up&lt;/a&gt;. In your project you can simply run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; cypress
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Project Used In This Tutorial
&lt;/h3&gt;

&lt;p&gt;As I mentioned, I created a Next.js app that we'll use as an existing codebase to cover with tests on this page. It's an error tracking tool similar to Sentry or Rollbar. You can find &lt;a href="https://prolog.profy.dev/dashboard" rel="noopener noreferrer"&gt;the running app here&lt;/a&gt;.&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%2Fmedia.graphassets.com%2FupYNfgzTL6PhGhTwgMA4" 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%2Fmedia.graphassets.com%2FupYNfgzTL6PhGhTwgMA4" alt="02-example-app-for-react-cypress-tests.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The app belongs to the &lt;a href="https://profy.dev" rel="noopener noreferrer"&gt;React Job Simulator program&lt;/a&gt; where you can learn and apply professional React dev skills like testing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I personally am a learning-by-doing type. So &lt;strong&gt;I highly recommend following along with this tutorial&lt;/strong&gt;. From my experience just reading only gets you this far. But applying the newly gained knowledge will make it stick. To get the source code drop your email below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/cypress-react#nl-5776319l5j5l8" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhj01d35x9k4hir3mp25.png" alt="Click here to get the source code for this tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What To Test
&lt;/h3&gt;

&lt;p&gt;In this tutorial we will test two things: The navigation bar (see screenshot below) and a list of issues that &lt;a href="https://prolog.profy.dev/dashboard/issues" rel="noopener noreferrer"&gt;you can see here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Let’s start with the navigation bar.&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%2Fmedia.graphassets.com%2FYjS6xhKqSpmF1VwEItTr" 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%2Fmedia.graphassets.com%2FYjS6xhKqSpmF1VwEItTr" alt="04-react-cypress-simple-ui-tests.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Cypress (as well as React Testing Library) we typically test an application the same way a user would interact with it. For example, we click on an element and see if the browser shows the correct result. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The purpose of a test is to ensure that a feature works correctly.&lt;/strong&gt; Not that a component gets the right props or a certain callback was run. That’s not what the user sees or is interested in. Shortly it’s irrelevant. &lt;/p&gt;

&lt;p&gt;There are lots of things that we could potentially test. But &lt;strong&gt;it’s a good idea to focus on the important parts of a feature’s functionality&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this case, the sidebar navigation serves its purpose if&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the links send the user to the correct page&lt;/li&gt;
&lt;li&gt;the navigation bar is collapsible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are relatively simple UI tests that we'll implement in the following two sections. Testing the issues page is a bit more complex as it involves API requests. We'll have a look at that in the 4th section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Navigation Links
&lt;/h2&gt;

&lt;p&gt;First, let's focus on the links in the navigation. Here is one way of testing them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We get the links in the navigation.&lt;/li&gt;
&lt;li&gt;We click each link.&lt;/li&gt;
&lt;li&gt;We check the URL to ensure that the correct page has opened.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Opening A URL With Cypress
&lt;/h3&gt;

&lt;p&gt;First, we need to do some setting up. Before each test, we need to open the application from within Cypress (here the home page works well). This is done via the &lt;a href="https://docs.cypress.io/api/commands/visit" rel="noopener noreferrer"&gt;cy.visit()&lt;/a&gt; command.&lt;/p&gt;

&lt;p&gt;Open the file &lt;code&gt;cypress/integration/navigation.spec.ts&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sidebar Navigation&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="nf"&gt;beforeEach&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;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visit&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/dashboard&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;But how do we get the links? First, it’s a good idea to get an overview of the navigation DOM structure. In our normal browser, we can open the dev tools and inspect the navigation.&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%2Fmedia.graphassets.com%2FSe2J1wnSlGeUwCNdm6kG" 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%2Fmedia.graphassets.com%2FSe2J1wnSlGeUwCNdm6kG" alt="05-react-cypress-inpsect-html-element.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing An Element Globally
&lt;/h3&gt;

&lt;p&gt;All the links are grouped in a &lt;code&gt;nav&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;Since there are other links on the page it’s smart to start with that group. We can access an element with the &lt;a href="https://docs.cypress.io/api/commands/get" rel="noopener noreferrer"&gt;cy.get()&lt;/a&gt; command. This command accepts a selector as a parameter (the tag &lt;code&gt;nav&lt;/code&gt; here) and returns all corresponding elements on the website.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sidebar Navigation&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="nf"&gt;beforeEach&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;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visit&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/dashboard&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;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;links are working&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&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;Easy. Now let’s double-check that everything’s working fine.&lt;/p&gt;

&lt;p&gt;In the Cypress UI, we click on &lt;code&gt;navigation.spec.ts&lt;/code&gt;. This should run the tests which looks like this:&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%2Fmedia.graphassets.com%2F043lpr1T5Ke5fo3TcqsZ" 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%2Fmedia.graphassets.com%2F043lpr1T5Ke5fo3TcqsZ" alt="06-1-react-cypress-test-pass"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If Cypress doesn’t find the element in question it throws an error.&lt;/strong&gt; But the test passes so everything is alright. Accessing the &lt;code&gt;nav&lt;/code&gt; element via &lt;code&gt;cy.get("nav")&lt;/code&gt; worked.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching Viewports
&lt;/h3&gt;

&lt;p&gt;But wait. Where is the navigation bar?&lt;/p&gt;

&lt;p&gt;Have a close look at the Cypress browser. This is the mobile view. And on mobile the navigation is hidden.&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%2Fmedia.graphassets.com%2F1u2tZANfSeK9y3pewVfc" 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%2Fmedia.graphassets.com%2F1u2tZANfSeK9y3pewVfc" alt="06-react-cypress-mobile-viewport.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That means we first need to set the viewport to desktop. That can be done with the &lt;a href="https://docs.cypress.io/api/commands/viewport" rel="noopener noreferrer"&gt;cy.viewport()&lt;/a&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sidebar Navigation&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="nf"&gt;beforeEach&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;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1025&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visit&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/dashboard&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;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;links are working&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&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;When you save the file the test should automatically re-run. Now our Cypress UI should show this:&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%2Fmedia.graphassets.com%2FGF4UsystQdqwCuIRrbiO" 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%2Fmedia.graphassets.com%2FGF4UsystQdqwCuIRrbiO" alt="07-react-cypress-desktop-viewport.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing A Specific Element By Text
&lt;/h3&gt;

&lt;p&gt;Now let’s test the first link. Since the “Projects” link points to the route &lt;code&gt;/&lt;/code&gt; (which is the current route) we test the “Issues” link first.&lt;/p&gt;

&lt;p&gt;The problem is that there are multiple links in the navigation. The &lt;code&gt;cy.get()&lt;/code&gt; command that we used before doesn't work well in this case. It would get all links on the whole page. But we want a specific one. The one inside the navigation that says “Issues”.&lt;/p&gt;

&lt;p&gt;To get an element by its text content we can use the &lt;a href="https://docs.cypress.io/api/commands/contains" rel="noopener noreferrer"&gt;contains()&lt;/a&gt; command. To make it even more specific we can chain it with the &lt;code&gt;get()&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;links are working&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="c1"&gt;// check that issues link leads to the right page&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Issues&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Interacting With Elements - Clicking
&lt;/h3&gt;

&lt;p&gt;Now we should have access to the "Issues" link and can interact with it. To click the link we can simply use the &lt;a href="https://docs.cypress.io/api/commands/click" rel="noopener noreferrer"&gt;click()&lt;/a&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;links are working&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="c1"&gt;// check that issues link leads to the right page&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&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 test should run again and hopefully pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cypress Helps With Debugging
&lt;/h3&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%2Fmedia.graphassets.com%2FdkA9bGGcQQSOQXsiMNxO" 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%2Fmedia.graphassets.com%2FdkA9bGGcQQSOQXsiMNxO" alt="08-react-cypress-hover-clicked-element.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s time for some Cypress magic. In the screenshot above do you see what happens when you hover over the “click” step on the left? It highlights the element that was clicked in the browser.&lt;/p&gt;

&lt;p&gt;This is super helpful to understand what’s going on and debug issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing The URL
&lt;/h3&gt;

&lt;p&gt;OK, looks like everything is fine for now.&lt;/p&gt;

&lt;p&gt;The last step to test the link is to check that the correct page is opened. As mentioned above we can simply check the URL. We can use the &lt;a href="https://docs.cypress.io/api/commands/url" rel="noopener noreferrer"&gt;cy.url()&lt;/a&gt; command and test its value with the &lt;a href="https://docs.cypress.io/api/commands/should" rel="noopener noreferrer"&gt;should()&lt;/a&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;links are working&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="c1"&gt;// check that issues link leads to the right page&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eq&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;http://localhost:3000/dashboard/issues&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;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fmedia.graphassets.com%2F1ALgWG3Qwa1T2w7ZeldA" 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%2Fmedia.graphassets.com%2F1ALgWG3Qwa1T2w7ZeldA" alt="09-react-cypress-tests-pass.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The test passes. Everything is as expected, yay!&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercise
&lt;/h3&gt;

&lt;p&gt;Now is your chance to get your hands dirty. We created a test for the first link here. But there are a few links that need to be tested as well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Projects&lt;/li&gt;
&lt;li&gt;Alerts&lt;/li&gt;
&lt;li&gt;Users&lt;/li&gt;
&lt;li&gt;Settings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: You can add all these tests to the same &lt;code&gt;it("links are working", ...)&lt;/code&gt; test case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/cypress-react#nl-5776319l5j5l8" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhj01d35x9k4hir3mp25.png" alt="Click here to get the source code for this tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing That The Navigation Is Collapsible
&lt;/h2&gt;

&lt;p&gt;Now let’s test a dynamic part of the sidebar navigation. When you click the”Collapse” button at the bottom left (either on your local machine or &lt;a href="https://prolog.profy.dev/" rel="noopener noreferrer"&gt;here&lt;/a&gt;) you should see the navigation bar collapse.&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%2Fmedia.graphassets.com%2FfJwdYG9ITSesjcoeHJ4W" 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%2Fmedia.graphassets.com%2FfJwdYG9ITSesjcoeHJ4W" alt="10-react-cypress-test-dynamic-element.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Clicking A Button
&lt;/h3&gt;

&lt;p&gt;We start with another &lt;code&gt;it(...)&lt;/code&gt; wrapper. Same as in the tests before we get the &lt;code&gt;nav&lt;/code&gt; element and find the “Collapse” button inside using &lt;code&gt;cy.get()&lt;/code&gt; and &lt;code&gt;cy.contains()&lt;/code&gt;. Finally we click it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is collapsible&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="c1"&gt;// collapse navigation&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Collapse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FFrZUd4YdSB2p0lkjzwAO" 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%2Fmedia.graphassets.com%2FFrZUd4YdSB2p0lkjzwAO" alt="11-react-cypress-tests-pass.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you check the Cypress UI the test passes and the navigation is collapsed. Everything seems to work fine. Again you can hover on each of the steps on the left to see what happened in the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  What To Test
&lt;/h3&gt;

&lt;p&gt;Now how do we test that the navigation is collapsed and ensure that it works? There are two things that seem sufficient to me:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check that all links are rendered and work correctly.&lt;/li&gt;
&lt;li&gt;Check that the text next to the icon is hidden.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Testing The Links
&lt;/h3&gt;

&lt;p&gt;Let’s start with the links. Since we tested each link’s target in the previous test I don’t think we need to do that again. Instead we can check that the correct number of links is rendered and that any of these is works correctly.&lt;/p&gt;

&lt;p&gt;To get all links, we can use the &lt;a href="https://docs.cypress.io/api/commands/find" rel="noopener noreferrer"&gt;cy.find()&lt;/a&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is collapsible&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="c1"&gt;// collapse navigation&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Collapse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// check that links still exist&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&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="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;have.length&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&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 we can take any one of these links and check that it still leads the user to the correct page. To access a specific element from an array Cypress provides the &lt;a href="https://docs.cypress.io/api/commands/first" rel="noopener noreferrer"&gt;first()&lt;/a&gt;, &lt;a href="https://docs.cypress.io/api/commands/eq" rel="noopener noreferrer"&gt;eq()&lt;/a&gt;, or &lt;a href="https://docs.cypress.io/api/commands/last" rel="noopener noreferrer"&gt;last()&lt;/a&gt; commands. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;cy.first()&lt;/code&gt; doesn’t work in our case since that would be the “Projects” link which is the current page. The test would pass even if the link didn’t do anything. &lt;code&gt;cy.last()&lt;/code&gt; seems a bit more fragile. It would break if we’d add another link to the navigation. &lt;/p&gt;

&lt;p&gt;So let’s settle for &lt;code&gt;cy.eq()&lt;/code&gt;. This would still break if we change the order of the links but seems like the least fragile option.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is collapsible&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="c1"&gt;// collapse navigation&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Collapse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// check that links still exist and are functional&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&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="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;have.length&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&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="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eq&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;http://localhost:3000/dashboard/issues&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing That Elements Are Hidden
&lt;/h3&gt;

&lt;p&gt;Finally, let’s check that the user only sees the icons and not the text next to them. Testing one link should be the same as they’re handled by a single component. So let’s use the “Issues” link.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;is collapsible&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="c1"&gt;// collapse navigation&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Collapse&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// check that links still exist and are functional&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&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="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;have.length&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&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="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eq&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;http://localhost:3000/dashboard/issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// check that text is not rendered&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;not.exist&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;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fmedia.graphassets.com%2FdmaPWDKRM6EEtfaAZgL7" 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%2Fmedia.graphassets.com%2FdmaPWDKRM6EEtfaAZgL7" alt="12-react-cypress-tests-pass.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great, we added our first simple UI tests. There are other things that we could test (like the navigation on mobile devices). But more on that later. Let’s continue with testing data-driven components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Pages With API Requests
&lt;/h2&gt;

&lt;p&gt;If you &lt;a href="https://prolog.profy.dev" rel="noopener noreferrer"&gt;visit the app’s projects page&lt;/a&gt; and look carefully (or with a sufficiently slow internet connection) you can see this loading state. This indicates that the page loads data from an API.&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%2Fmedia.graphassets.com%2F0vmtv6KfTkq8VCtcfydB" 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%2Fmedia.graphassets.com%2F0vmtv6KfTkq8VCtcfydB" alt="13-react-cypress-loading-state.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To be fair, this is not the best loading indicator but that’s a task for the React Job Simulator.&lt;/p&gt;

&lt;p&gt;Once the data is loaded we see the projects rendered on the page.&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%2Fmedia.graphassets.com%2FlZUDVUwVTFiReUCUcNJL" 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%2Fmedia.graphassets.com%2FlZUDVUwVTFiReUCUcNJL" alt="14-react-cypress-remote-data.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What To Test
&lt;/h3&gt;

&lt;p&gt;Now, how do we test this data?&lt;/p&gt;

&lt;p&gt;Again like a user would use the app. We get the elements on the page (here the project cards) and check that the correct values are rendered.&lt;/p&gt;

&lt;p&gt;First, let's again get an overview of the DOM structure. When you inspect the first project card in your dev tools you’ll see this:&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%2Fmedia.graphassets.com%2FHW1bI4R9SwWPt5rqXo9G" 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%2Fmedia.graphassets.com%2FHW1bI4R9SwWPt5rqXo9G" alt="15-react-cypress-inpsect-html-element.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that each project card is wrapped in a &lt;code&gt;li&lt;/code&gt; tag. This seems like a good selector for our tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing Elements Within A Parent
&lt;/h3&gt;

&lt;p&gt;The problem is that we know from the previous tests that there are &lt;code&gt;li&lt;/code&gt; elements in the navigation bar as well. So when we try to access the project cards we need to be careful not to grab the navigation links.&lt;/p&gt;

&lt;p&gt;The easiest way to prevent this is to identify a suitable parent element of the project cards and access this first. Here the &lt;code&gt;main&lt;/code&gt; element seems like a good fit since the navigation is rendered outside of it.&lt;/p&gt;

&lt;p&gt;That’s enough information for now. Open the file &lt;code&gt;cypress/integration/project-list.spec.ts&lt;/code&gt; and add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Project List&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="nf"&gt;beforeEach&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;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1025&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visit&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/dashboard&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;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renders the projects&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="c1"&gt;// get all project cards&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&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;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;li&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;h3&gt;
  
  
  Iterating Over A List Of Elements
&lt;/h3&gt;

&lt;p&gt;Now we can make use of the &lt;a href="https://docs.cypress.io/api/commands/each" rel="noopener noreferrer"&gt;each($el ⇒ …)&lt;/a&gt; command to iterate through this list. The first parameter &lt;code&gt;$el&lt;/code&gt; of the callback function allows us to access each element. &lt;/p&gt;

&lt;p&gt;So to test that e.g. the first card contains the project title “Frontend - Web” it makes sense to simply try to write &lt;code&gt;$el.contains("Frontend - Web")&lt;/code&gt;. Unfortunately, this gives us an error.&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%2Fmedia.graphassets.com%2FZpCiapljSNGvHJnnm2kJ" 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%2Fmedia.graphassets.com%2FZpCiapljSNGvHJnnm2kJ" alt="16-react-cypress-each-loop.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The type of the parameter &lt;code&gt;$el&lt;/code&gt; is &lt;code&gt;JQuery&amp;lt;HTMLElement&amp;gt;&lt;/code&gt;. And this doesn’t support the Cypress commands like &lt;code&gt;contains()&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Looking at the docs there is a simple solution though: we can just wrap &lt;code&gt;$el&lt;/code&gt; with &lt;a href="https://docs.cypress.io/api/commands/wrap" rel="noopener noreferrer"&gt;cy.wrap()&lt;/a&gt; and access all Cypress commands as we’re used to.&lt;/p&gt;

&lt;p&gt;So let’s test the first project card. For now, we simply hard-code the expected values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Project List&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="nf"&gt;beforeEach&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;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1025&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visit&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/dashboard&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;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renders the projects&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="c1"&gt;// get all project cards&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&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;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;li&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;each&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;$el&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="c1"&gt;// only test the first project card&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;index&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="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Frontend - Web&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&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="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;73&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;12&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&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="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;have.attr&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;href&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;/issues&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;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FkV5oHfCmRVyTlDuXLg8k" 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%2Fmedia.graphassets.com%2FkV5oHfCmRVyTlDuXLg8k" alt="17-react-cypress-tests-pass.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, all tests pass. That tells us that the overall approach works. But obviously hard-coding the expected data and wrapping it in an &lt;code&gt;if&lt;/code&gt; clause isn’t really an option. There are two problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The tests would get unnecessarily long.&lt;/li&gt;
&lt;li&gt;What happens when the data returned by the server changes? The tests would fail.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Detour: Different Types Of Testing
&lt;/h3&gt;

&lt;p&gt;In order to make these tests pass reliably, &lt;strong&gt;we need to always have the same data&lt;/strong&gt;. There are two ways of achieving that&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we have a server that always delivers the expected data&lt;/li&gt;
&lt;li&gt;we mock the responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In larger projects, you often find test environments that include databases, servers, and so on. This is a great way to test the application from the database to the frontend. &lt;strong&gt;These tests are also called “end-to-end test”.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here we don’t have such a test server so we’ll mock the responses. This way we only test the frontend isolated from the rest of the system. &lt;strong&gt;This is called an integration test.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want to read more about the different types of testing and their advantages &lt;a href="https://kentcdodds.com/blog/write-tests" rel="noopener noreferrer"&gt;read this awesome blog post by Kent C. Dodds&lt;/a&gt;. As a summary, he argues that &lt;strong&gt;integration tests usually get you the most bang for the buck&lt;/strong&gt;. They are relatively performant (better than end-to-end tests but worse than unit tests) and give you good confidence that your application is functioning (less than e2e but more than unit tests).&lt;/p&gt;

&lt;p&gt;Note that Cypress is probably not the best tool to use for perfomant tests. That would rather be Jest + React Testing Library. But as I said earlier, it’s a better option for beginners due to the easy setup and visual feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mocking Requests/Responses With Cypress
&lt;/h3&gt;

&lt;p&gt;So we decided to write integration tests by mocking out our API requests. The first step is preparing our mock data. There are a few options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write the data by hand.&lt;/li&gt;
&lt;li&gt;Use a tool to create random data from a schema.&lt;/li&gt;
&lt;li&gt;Use existing API data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our case, we already have a working API. So we can simply copy our mock data from one of the requests. The easiest way to access this data is via the browser’s dev tools:&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%2Fmedia.graphassets.com%2FeYCb7pjISZ6JlrWqzrlj" 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%2Fmedia.graphassets.com%2FeYCb7pjISZ6JlrWqzrlj" alt="18-react-cypress-prepare-fixture-or-mock-data.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get data from any request in Chrome simply follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the “Network” tab.&lt;/li&gt;
&lt;li&gt;Filter the requests by “Fetch/XHR”.&lt;/li&gt;
&lt;li&gt;Click on the “project” request.&lt;/li&gt;
&lt;li&gt;Open the “Preview” tab.&lt;/li&gt;
&lt;li&gt;Right-click below the data and click “Copy object”.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cypress has a separate folder for mock data at &lt;code&gt;cypress/fixtures&lt;/code&gt;. &lt;a href="https://stackoverflow.com/questions/12071344/what-are-fixtures-in-programming" rel="noopener noreferrer"&gt;A fixture in our case is simply the mock data that makes our tests repeatable.&lt;/a&gt; Create a file in that folder called &lt;code&gt;projects.json&lt;/code&gt; and paste the data you copied above there.&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%2Fmedia.graphassets.com%2FYnq8HADxRcSIlu1hC6bT" 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%2Fmedia.graphassets.com%2FYnq8HADxRcSIlu1hC6bT" alt="19-react-cypress-prepare-fixture-or-mock-data.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mocking the response to this request is now simple with the &lt;a href="https://docs.cypress.io/api/commands/intercept" rel="noopener noreferrer"&gt;cy.intercept()&lt;/a&gt; command. You can get the URL of the API endpoint again from the network tab in the browser’s dev tools.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// setup request mock&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;intercept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&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;https://prolog-api.profy.dev/project&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;fixture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;projects.json&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;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;getProjects&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// set desktop viewport&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1025&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visit&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/dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// wait for the projects response&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@getProjects&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code we also use the &lt;a href="https://docs.cypress.io/api/commands/as" rel="noopener noreferrer"&gt;as()&lt;/a&gt; command to create an alias. We can use this alias to &lt;a href="https://docs.cypress.io/api/commands/wait" rel="noopener noreferrer"&gt;wait&lt;/a&gt; for the response before the tests start. This is useful to prevent the tests from randomly failing due to timing issues (aka making them less “flaky”).&lt;/p&gt;

&lt;p&gt;When you re-run the test now you should receive the mock data. You can double-check that the test doesn’t send real requests either by &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;changing something inside the mock data or&lt;/li&gt;
&lt;li&gt;checking the request in the Cypress UI (as shown in the screenshot below).&lt;/li&gt;
&lt;/ul&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%2Fmedia.graphassets.com%2FWDi0ixmQOuHlsUzXnGOM" 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%2Fmedia.graphassets.com%2FWDi0ixmQOuHlsUzXnGOM" alt="20-react-cypress-validate-mock-request-with-intercept.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Asserting Against The Mock Data
&lt;/h3&gt;

&lt;p&gt;Remember that we hard-coded the expected data for the first project card in the test? Now we can replace it with the data from our fixture.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;capitalize&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lodash/capitalize&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;mockProjects&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;../fixtures/projects.json&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;ProjectLanguage&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;features/projects/types/project.types&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Project List&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="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// setup request mock&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;intercept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&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;https://prolog-api.profy.dev/project&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;fixture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;projects.json&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;as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;getProjects&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1025&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visit&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/dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@getProjects&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;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renders the projects&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;languageNames&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="nx"&gt;ProjectLanguage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;react&lt;/span&gt;&lt;span class="p"&gt;]:&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ProjectLanguage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Node.js&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;ProjectLanguage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Python&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="c1"&gt;// get all project cards&lt;/span&gt;
    &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&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;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;li&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;each&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;$el&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectLanguage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mockProjects&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="nx"&gt;language&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ProjectLanguage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// check that project data is rendered&lt;/span&gt;
        &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mockProjects&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="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;languageNames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;projectLanguage&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mockProjects&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="nx"&gt;numIssues&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mockProjects&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="nx"&gt;numEvents24h&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;capitalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mockProjects&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="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&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="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;have.attr&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;href&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;/issues&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;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we need to add some additional logic. The reason is that in some cases, the data is changed by the frontend before displaying it to the user. For example, the project language can be &lt;code&gt;node&lt;/code&gt; in the response data but will be displayed as &lt;code&gt;Node.js&lt;/code&gt;.&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%2Fmedia.graphassets.com%2F5WGolQDhSl6yraf9r2q8" 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%2Fmedia.graphassets.com%2F5WGolQDhSl6yraf9r2q8" alt="21-react-cypress-alter-remote-data.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging Broken Tests
&lt;/h2&gt;

&lt;p&gt;When you write your own tests you will run into problems at some point. So it’s important that you know how to debug your tests.&lt;/p&gt;

&lt;p&gt;I prepared an example for a failing test in the file &lt;code&gt;cypress/integration/issue-list.spec.ts&lt;/code&gt; for us to debug together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renders the issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&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;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tr&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;each&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;$el&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;issue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mockIssues1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstLineOfStackTrace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issue&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="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issue&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;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;numEvents&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firstLineOfStackTrace&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 looks pretty similar to the test for the project pages. It’s supposed to check that the data inside the issues table is rendered correctly.&lt;/p&gt;

&lt;p&gt;But when you run it you’ll see that there’s an error:&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%2Fmedia.graphassets.com%2FmBFto0vdThmdxTdpEIfC" 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%2Fmedia.graphassets.com%2FmBFto0vdThmdxTdpEIfC" alt="22-react-cypress-debug-test.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: you can tell Cypress to only run a certain test or set of tests by appending &lt;code&gt;.only&lt;/code&gt; to &lt;code&gt;describe&lt;/code&gt; or &lt;code&gt;it&lt;/code&gt;. This way you don’t have to wait for all tests to run while you’re working on a single test. In our case, we can write &lt;code&gt;it.only("renders the issues", () =&amp;gt; {&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The error above looks strange: &lt;code&gt;Cannot read properties of undefined (reading 'stack')&lt;/code&gt;. It’s not immediately clear what that means.&lt;/p&gt;

&lt;p&gt;So let’s dig deeper. But how to debug your tests?&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Chrome Dev Tools
&lt;/h3&gt;

&lt;p&gt;The answer is simple: You can do the same things that you can do in your normal Chrome browser as well. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inspect DOM elements&lt;/li&gt;
&lt;li&gt;Print out variables with console.log() from either your code or your tests&lt;/li&gt;
&lt;li&gt;Add breakpoints to stop code execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our case, we can start by investigating the test file. We could add &lt;code&gt;console.log()&lt;/code&gt; statements in the code. But let’s be a bit more professional and use the debugger.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Breakpoints
&lt;/h3&gt;

&lt;p&gt;First, open the dev tools inside your Cypress UI. You can do that either with your usual key combination or by right-clicking somewhere in the browser window and clicking “Inspect”&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%2Fmedia.graphassets.com%2FpT5eGXLcS3GRvnLznzdF" 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%2Fmedia.graphassets.com%2FpT5eGXLcS3GRvnLznzdF" alt="23-react-cypress-debug-test-with-dev-tools-inspect.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next click on the “Sources” tab. You should see a hint on how to open a file (in my case &lt;strong&gt;⌘&lt;/strong&gt; + P).&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%2Fmedia.graphassets.com%2F8ouje7AQ81UC134E3pfg" 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%2Fmedia.graphassets.com%2F8ouje7AQ81UC134E3pfg" alt="23-react-cypress-debug-test-with-dev-tools-breakpoint.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you start typing the file name you want to investigate. In this case, “issue-list” should be sufficient to get the correct results.&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%2Fmedia.graphassets.com%2FHiEkfwSQGpOFE2V6SJmw" 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%2Fmedia.graphassets.com%2FHiEkfwSQGpOFE2V6SJmw" alt="24-react-cypress-debug-test-with-dev-tools-breakpoint.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that you can also open the React component (”issue-list.tsx”) which means you can also debug your application code&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you opened the file you can add a breakpoint. The error message at the left of the Cypress UI tells us that something is wrong in the &lt;code&gt;.each&lt;/code&gt; loop. So let’s start there:&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%2Fmedia.graphassets.com%2FBGIgVqHJQqGD0sHGyOQu" 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%2Fmedia.graphassets.com%2FBGIgVqHJQqGD0sHGyOQu" alt="25-react-cypress-debug-test-with-dev-tools-breakpoint.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that I only added one breakpoint. The second appeared by itself. I guess that’s because internally we debug a JS file that is mapped back to its original TS source.&lt;/p&gt;

&lt;p&gt;Now we can re-run the test by pressing the refresh button inside the top bar. The code execution should stop within the &lt;code&gt;.each()&lt;/code&gt; loop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inpsecting Variables
&lt;/h3&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%2Fmedia.graphassets.com%2FvYad8LrFSeKcEbr6eRHJ" 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%2Fmedia.graphassets.com%2FvYad8LrFSeKcEbr6eRHJ" alt="26-react-cypress-debug-test-with-dev-tools-breakpoint-variables.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now isn’t this magic? &lt;/p&gt;

&lt;p&gt;We can inspect the variables (specifically &lt;code&gt;$el&lt;/code&gt; ) in the right-side menu. We can already see from the class name that this is the header row of the table. But when we hover over the class name it even highlights the element in the UI above. 🤯&lt;/p&gt;

&lt;p&gt;The problem is clear now (at least to me since I wrote the test): We wanted to test that the data inside the table is rendered correctly. But the first item we get is the header row which doesn’t contain any data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inspecting DOM Elements
&lt;/h3&gt;

&lt;p&gt;As we’ve done before we need to narrow down the search for the correct elements. Let’s look at the DOM structure again to see our options. When you inspect the table with your dev tools you can see this:&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%2Fmedia.graphassets.com%2FKgTZo71kRIuhDKDALGlK" 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%2Fmedia.graphassets.com%2FKgTZo71kRIuhDKDALGlK" alt="27-react-cypress-debug-test-dev-tools.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The table rows that contain the data are wrapped in a &lt;code&gt;&amp;lt;tbody&amp;gt;&lt;/code&gt; tag. So we can use this information to filter out the table header row from our test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renders the issues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&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;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tbody&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;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tr&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;each&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;$el&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;issue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mockIssues1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstLineOfStackTrace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issue&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="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issue&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;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;numEvents&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$el&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;firstLineOfStackTrace&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The test should pass now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Turn - More Exercises
&lt;/h2&gt;

&lt;p&gt;If your fingers are itchy and you want to try this stuff out yourself here is the good news: There are a few test cases left that you can implement yourself.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The issue list has a pagination at the bottom. You can test that the buttons are working correctly and that the right data is rendered.&lt;/li&gt;
&lt;li&gt;The page number of this pagination should persist after a refresh.&lt;/li&gt;
&lt;li&gt;On mobile devices, the sidebar navigation should not be visible initially and be toggled by the menu button in the header.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that the last test is a bit more complex. Cypress doesn’t have a native way to test if an element is outside the viewport. &lt;a href="https://github.com/cypress-io/cypress/issues/877" rel="noopener noreferrer"&gt;I found this GitHub issue to be helpful&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to try these exercises you can either implement the tests against the deployed version of the app that I shared at the beginning of the page. Or you drop you email below to get access to the source code. There you can also find my implementations of these tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/cypress-react#nl-5776319l5j5l8" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhj01d35x9k4hir3mp25.png" alt="Click here to get the source code for this tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How To Debug React Apps With VS Code - Boost Your Debugging Productivity</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Fri, 16 Sep 2022 12:09:50 +0000</pubDate>
      <link>https://forem.com/profydev/how-to-debug-react-apps-with-vs-code-boost-your-debugging-productivity-1k05</link>
      <guid>https://forem.com/profydev/how-to-debug-react-apps-with-vs-code-boost-your-debugging-productivity-1k05</guid>
      <description>&lt;p&gt;Debugging a React app can be a slow and painful process. Adding a &lt;code&gt;console.log()&lt;/code&gt; statement here and there until you’re finally in the right spot. Or a more advanced version: Jumping around between setting breakpoints in the Chrome dev tools and editing code in your IDE until the bug is fixed.&lt;/p&gt;

&lt;p&gt;But with the right tools and a strategic approach debugging can become much easier. Maybe even fun?!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Turns out much beloved VS Code makes it very simple&lt;/strong&gt; to debug a React app directly from the IDE. The result: Super easy setup and a more productive debugging workflow.&lt;/p&gt;

&lt;p&gt;On this page, you can see &lt;strong&gt;how to set up VS Code as a debugger for your React app and see it in action&lt;/strong&gt;. We’ll debug a small problem with a Next.js application and use (conditional) breakpoints, step into functions, and inspect and edit variables directly from the VS Code. All of this paired with a structured debugging approach and the bug is fixed in no time.&lt;/p&gt;

&lt;p&gt;Here’s a short video showing how to set up and use the VS Code debugger. Alternatively, you can find a detailed step-by-step tutorial with screenshots on this page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/debug-react-vscode#nl-5771155o6i9g5" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdae6h4l55326gscikj4e.png" alt="Click here to get the source code for this tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Launch Chrome via VS Code&lt;/li&gt;
&lt;li&gt;Using The VS Code Debugger&lt;/li&gt;
&lt;li&gt;
The VS Code Debugger In Action

&lt;ol&gt;
&lt;li&gt;Using Breakpoints in VS Code&lt;/li&gt;
&lt;li&gt;Conditional Breakpoints To The Rescue&lt;/li&gt;
&lt;li&gt;Finding The Root Cause&lt;/li&gt;
&lt;li&gt;Inspect And Edit Variables In The Debugger&lt;/li&gt;
&lt;li&gt;Step Into A Function&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  Launch Chrome via VS Code
&lt;/h2&gt;

&lt;p&gt;Starting to debug your React app with the VS Code debugger is surprisingly simple. You let VS Code create a &lt;code&gt;launch.json&lt;/code&gt; config for you and slightly adjust it. You can find the file in the &lt;code&gt;.vsocde&lt;/code&gt; folder in your repository.&lt;/p&gt;

&lt;p&gt;Depending on your app you need to &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;adjust the &lt;code&gt;url&lt;/code&gt; field (here I change the port to 3000)&lt;/li&gt;
&lt;li&gt;adjust the &lt;code&gt;webRoot&lt;/code&gt; entry (e.g. if your code is in the &lt;code&gt;src&lt;/code&gt; folder like create-react-app apps you change &lt;code&gt;${workspaceFolder}&lt;/code&gt; to &lt;code&gt;${workspaceFolder}/src&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&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%2Fmedia.graphassets.com%2FWuWfoWNuQKKm9uArfbLV" 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%2Fmedia.graphassets.com%2FWuWfoWNuQKKm9uArfbLV" alt="react-debug-vscode-setup-launch-config.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can hit the play button ▶️ to start a Chrome browser in debug mode. The VS Code debugger is automatically attached to this browser.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: You could run Chrome in debug mode manually and use the “attach” launch config to attach the VS Code debugger. But I don’t see a reason to overcomplicate things.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you already have a &lt;code&gt;launch.json&lt;/code&gt; file or want to add another config to it you can simply use Intellisense (e.g. by pressing cmd + space on Mac) and get suggestions.&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%2Fmedia.graphassets.com%2FTBM1uQyTjeMZY9O2st8r" 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%2Fmedia.graphassets.com%2FTBM1uQyTjeMZY9O2st8r" alt="react-debug-vscode-add-config-with-intellisense.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is my &lt;code&gt;launch.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;version&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;0.2.0&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;configurations&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;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&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;Run Chrome&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;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chrome&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;request&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;launch&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;url&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;http://localhost:3000&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;webRoot&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;${workspaceFolder}&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;h2&gt;
  
  
  Using The VS Code Debugger
&lt;/h2&gt;

&lt;p&gt;Two use the debugger you need two things: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run your React app (e.g. by running &lt;code&gt;npm start&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Start Chrome via VS Code by pressing the play button ▶️.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can now use the debugger as you would in the Chrome dev tools. If you’re not familiar with that you can see an example below.&lt;/p&gt;

&lt;h2&gt;
  
  
  The VS Code Debugger In Action
&lt;/h2&gt;

&lt;p&gt;Let’s imagine the following situation: We’re a developer working on a Next.js app that is in production. Real users, nothing should break.&lt;/p&gt;

&lt;p&gt;One of the most important pages used to look like this (&lt;a href="https://prolog.profy.dev/dashboard/issues" rel="noopener noreferrer"&gt;you can see a deployed version of it here&lt;/a&gt;):&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%2Fmedia.graphassets.com%2FeMsrLvwMQdu5lE5hMzQR" 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%2Fmedia.graphassets.com%2FeMsrLvwMQdu5lE5hMzQR" alt="react-debug-vscode-website-without-bug.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But suddenly we get reports that something is broken (&lt;a href="https://debug.profy.dev/dashboard/issues" rel="noopener noreferrer"&gt;here a deployed version&lt;/a&gt;):&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%2Fmedia.graphassets.com%2FPCEc4OLeSrWSj0QBhHga" 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%2Fmedia.graphassets.com%2FPCEc4OLeSrWSj0QBhHga" alt="react-debug-vscode-website-production-error.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Damn, how did this bug make it into production? Our customers are upset. They’re paying good money and rely on our app. Obviously, our managers are going crazy as well.&lt;/p&gt;

&lt;p&gt;But we as the developers stay calm. With the right debugging approach we can probably fix this bug in no time.&lt;/p&gt;

&lt;p&gt;The error message in production doesn’t tell us a lot. So first we run the app on our local machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/debug-react-vscode#nl-5771155o6i9g5" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4oc8zmd30u0d6ajua3i.png" alt="Click here to get the source code for this tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we know that we need to debug the code we use the VS Code debugger to start a Chrome instance.&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%2Fmedia.graphassets.com%2FWNdRfN4sQ5KN3JJl5UuE" 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%2Fmedia.graphassets.com%2FWNdRfN4sQ5KN3JJl5UuE" alt="react-debug-vscode-run-chrome-in-debugging-mode.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This opens the browser at &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;localhost:3000&lt;/a&gt; as defined in launch.json.&lt;/p&gt;

&lt;p&gt;Now when we navigate to the problematic page we see this error.&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%2Fmedia.graphassets.com%2FkDrY81mATYajG2SDHwR3" 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%2Fmedia.graphassets.com%2FkDrY81mATYajG2SDHwR3" alt="react-debug-vscode-error-on-local-machine.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Breakpoints in VS Code
&lt;/h3&gt;

&lt;p&gt;This error is much better than what we see on the production website. It provides us with two important pieces of information: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The error message “Cannot read properties of null”.&lt;/li&gt;
&lt;li&gt;The name of the file and the line where the error occurred: line 49 in &lt;code&gt;issue-row.tsx&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Opening the file in VS Code is really simple. The file path in the error message is in fact a link:&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%2Fmedia.graphassets.com%2FmnZEHthTyqRdmqrrTHQ7" 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%2Fmedia.graphassets.com%2FmnZEHthTyqRdmqrrTHQ7" alt="react-debug-vscode-open-file-by-click-on-error-message.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we click it, the file &lt;code&gt;issue-row.tsx&lt;/code&gt; opens in VS Code. Magic.&lt;/p&gt;

&lt;p&gt;The error message tells us that the &lt;code&gt;issue&lt;/code&gt; prop is likely &lt;code&gt;null&lt;/code&gt; at some point. Let’s verify that by adding a breakpoint. Simply click inside the empty space next to the line number.&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%2Fmedia.graphassets.com%2FVweOtmQR82Z6ettUg9pw" 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%2Fmedia.graphassets.com%2FVweOtmQR82Z6ettUg9pw" alt="react-debug-vscode-set-breakpoint-and-restart.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you press the green “Restart” button ↻ the page refreshes. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To speed up the process you can also use a key combination (Cmd + Shift + F5 in my case). You can hover over the button to find out yours.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The code execution stops at the breakpoint. At the same time, the website freezes in its loading state.&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%2Fmedia.graphassets.com%2FnqxDOLPySm25lxfLT83o" 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%2Fmedia.graphassets.com%2FnqxDOLPySm25lxfLT83o" alt="react-debug-vscode-code-execution-stops-at-breakpoint.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the screenshot above the &lt;code&gt;issue&lt;/code&gt; prop is defined during the first render.&lt;/p&gt;

&lt;p&gt;So we press the “Continue” button ⏯️ or F5 a couple of times. The problem is that there are quite a few &lt;code&gt;IssueRow&lt;/code&gt; components being rendered. So hitting “Continue” until we find the right issue becomes quickly annoying.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conditional Breakpoints To The Rescue
&lt;/h3&gt;

&lt;p&gt;Instead of hitting “Continue” all the time, we’d like to skip all the issues that are defined and only stop at the nullish one.&lt;/p&gt;

&lt;p&gt;The easiest way to do that is by adding a condition to the breakpoint. Right-click on the breakpoint and select “Edit Breakpoint”.&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%2Fmedia.graphassets.com%2F091BIU1eRkShz1l1047Z" 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%2Fmedia.graphassets.com%2F091BIU1eRkShz1l1047Z" alt="react-debug-vscode-edit-conditional-breakpoint.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can enter a JavaScript expression. In our case, we want to stop at &lt;code&gt;issue === null&lt;/code&gt;. &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%2Fmedia.graphassets.com%2F4d7hGOrARvNUiJ3ekPow" 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%2Fmedia.graphassets.com%2F4d7hGOrARvNUiJ3ekPow" alt="react-debug-vscode-add-expression-to-conditional-breakpoint.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We hit enter and continue code execution. And voila we can confirm that at least one issue is &lt;code&gt;null&lt;/code&gt;.&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%2Fmedia.graphassets.com%2F09zPLmcVTGmJHQXU3bue" 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%2Fmedia.graphassets.com%2F09zPLmcVTGmJHQXU3bue" alt="react-debug-vscode-inspect-variables.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To be honest, this isn’t exactly news to us as we already knew this from the error message. But at least we were able to confirm the problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding The Root Cause
&lt;/h3&gt;

&lt;p&gt;So let’s dig a bit deeper. In a simple JavaScript program, we could just follow the call stack or press the “Step Out” button (⬆️) to find the root cause of the problem.&lt;/p&gt;

&lt;p&gt;But with React (and other frameworks) it’s not that easy:&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%2Fmedia.graphassets.com%2FHlCoR3qQOuEeGFI4Sx05" 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%2Fmedia.graphassets.com%2FHlCoR3qQOuEeGFI4Sx05" alt="react-debug-vscode-callstack-react-internal-files.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Except the &lt;code&gt;IssueRow&lt;/code&gt; we can’t see any of our code files in the “Call Stack” panel. Everything else is internal React files.&lt;/p&gt;

&lt;p&gt;This doesn’t help us much.&lt;/p&gt;

&lt;p&gt;So, unfortunately, we need to find out where the &lt;code&gt;IssueRow&lt;/code&gt; component is rendered manually. The global search function of VS Code is our best friend here.&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%2Fmedia.graphassets.com%2FPcVECtifR8eE8a8sW0oQ" 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%2Fmedia.graphassets.com%2FPcVECtifR8eE8a8sW0oQ" alt="react-debug-vscode-global-search.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We open the file and add another breakpoint just before the return statement of the component.&lt;/p&gt;

&lt;p&gt;Then hit the refresh button ↻ in the debug controls or F5.&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%2Fmedia.graphassets.com%2FuH40b1IkSnmyQZxzejgy" 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%2Fmedia.graphassets.com%2FuH40b1IkSnmyQZxzejgy" alt="react-debug-vscode-inspect-variables-array.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great, now we see that one item in the &lt;code&gt;items&lt;/code&gt; array is indeed &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inspect And Edit Variables In The Debugger
&lt;/h3&gt;

&lt;p&gt;Our assumption is that this &lt;code&gt;null&lt;/code&gt; value causes the bug. But before we start messing around with our code we can easily verify this assumption by editing the variable inside the debugger.&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%2Fmedia.graphassets.com%2F720gtDXMRmKjwYZo6ZqD" 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%2Fmedia.graphassets.com%2F720gtDXMRmKjwYZo6ZqD" alt="react-debug-vscode-edit-variable-in-debugger.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we continue the code execution now we can see that the error disappears on the website. The 7th and 8th items in the issue list are now duplicates as expected.&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%2Fmedia.graphassets.com%2FWtJruFMRCORjuw3cMX7A" 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%2Fmedia.graphassets.com%2FWtJruFMRCORjuw3cMX7A" alt="react-debug-vscode-verify-fix.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This verifies our assumption that the &lt;code&gt;null&lt;/code&gt; value in the data array is the problem. &lt;/p&gt;

&lt;p&gt;That makes the solution to our bug simple: we can just filter out all &lt;code&gt;null&lt;/code&gt; values from the data to fix the bug. Of course, we could implement the filter function in the component. But maybe a place closer to the data source would be more suitable. This way other (future) components could potentially benefit from the same fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step Into A Function
&lt;/h3&gt;

&lt;p&gt;To dig a bit deeper we have a look at the beginning of the component. The &lt;code&gt;items&lt;/code&gt; array with the &lt;code&gt;null&lt;/code&gt; value comes from the &lt;code&gt;issuePage&lt;/code&gt; variable. And that one comes from a hook.&lt;/p&gt;

&lt;p&gt;So let’s set another breakpoint there and hit the refresh button again. Code execution stops at the breakpoint. &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%2Fmedia.graphassets.com%2FLE5aOIbDTDK12zq9NaAf" 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%2Fmedia.graphassets.com%2FLE5aOIbDTDK12zq9NaAf" alt="react-debug-vscode-step-into-hook.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can use the “Step Into” button ⬇️ to investigate that hook. The first file that opens is again some internal React file.&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%2Fmedia.graphassets.com%2FiVX1P0hqSlaGHMxYCLJw" 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%2Fmedia.graphassets.com%2FiVX1P0hqSlaGHMxYCLJw" alt="react-debug-vscode-step-into-hook-react-internal-file.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But this time we’re better off. After hitting the “Step Into” button a couple of times we end up in the &lt;code&gt;useIssues&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;Having a closer look the &lt;code&gt;getIssues&lt;/code&gt; function seems like a good candidate to filter the data.&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%2Fmedia.graphassets.com%2FwstZxkNkR8WTCJYNhzDb" 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%2Fmedia.graphassets.com%2FwstZxkNkR8WTCJYNhzDb" alt="react-debug-vscode-fix-1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately, for some reason, we neither can step into the &lt;code&gt;getIssues&lt;/code&gt; function nor does code execution stop at a breakpoint inside. If you have a bit of debugging experience you know that there are inconveniences like this from time to time.&lt;/p&gt;

&lt;p&gt;Anyway, let’s not allow that to hold us back. We add a bit of code to filter the issues.&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%2Fmedia.graphassets.com%2Ft9IcM62TBWyh7mrrq4RP" 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%2Fmedia.graphassets.com%2Ft9IcM62TBWyh7mrrq4RP" alt="react-debug-vscode-fix-2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we hit return we can confirm that the bug is fixed.&lt;/p&gt;

&lt;p&gt;Commit, push, deploy. Everyone’s happy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/debug-react-vscode#nl-5771155o6i9g5" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4oc8zmd30u0d6ajua3i.png" alt="Click here to get the source code for this tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Codebase Tour Through An Advanced React Project - How The Pieces Fit Together (incl video)</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Fri, 09 Sep 2022 11:58:56 +0000</pubDate>
      <link>https://forem.com/profydev/codebase-tour-through-an-advanced-react-project-how-the-pieces-fit-together-incl-video-2m94</link>
      <guid>https://forem.com/profydev/codebase-tour-through-an-advanced-react-project-how-the-pieces-fit-together-incl-video-2m94</guid>
      <description>&lt;p&gt;Have you tried looking at a professionally set up codebase?&lt;/p&gt;

&lt;p&gt;Just the appearance of it can be confusing. There are lots of folders and &lt;code&gt;.whatever&lt;/code&gt; files that you've never seen. You may have &lt;a href="https://profy.dev/article/react-folder-structure" rel="noopener noreferrer"&gt;a folder structure that feels uncomfortably different&lt;/a&gt; from your typical create-react-app folders.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;└── src/
    ├── components/
    ├── contexts/
    └── hooks/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On top of that, there’s usually a lot going on behind the scenes. For example, you have tools that help you&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep your code consistent&lt;/li&gt;
&lt;li&gt;detect potential bugs while you write the code&lt;/li&gt;
&lt;li&gt;test your app automatically to warn you when a feature is broken&lt;/li&gt;
&lt;li&gt;prevent merging broken code in the main branch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This can be confusing as heck. It's hard to grasp how different parts of the codebase are intertwined and how a developer gets code from their local machine to production. It's like a puzzle of a 1000 pieces that you have to assemble in your mind.&lt;/p&gt;

&lt;p&gt;Obviously, it would be great if you had a guide. Somebody with experience who explained to you how things work. And that's typically what you get when you start a developer job (at least if you're lucky). But before that you're on your own. Struggling to fit the pieces together. Or simply giving up.&lt;/p&gt;

&lt;p&gt;Good news though: For the past months, I’ve been working on such an advanced project for a training program. And you can get a tour through that codebase right now. To start with &lt;a href="https://github.com/profydev/prolog-app" rel="noopener noreferrer"&gt;here is the source code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I created this project based on my experiences from real-world projects as well as community recommendations. The project is built with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Feature-driven folder structure inspired by &lt;a href="https://github.com/alan2207/bulletproof-react" rel="noopener noreferrer"&gt;Bulletproof React&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ESLint for static code checks&lt;/li&gt;
&lt;li&gt;Prettier for consistent code formatting&lt;/li&gt;
&lt;li&gt;TypeScript for type checking&lt;/li&gt;
&lt;li&gt;Husky &amp;amp; lint-staged for pre-commit hooks&lt;/li&gt;
&lt;li&gt;Cypress for integration testing&lt;/li&gt;
&lt;li&gt;Jest for unit testing&lt;/li&gt;
&lt;li&gt;Storybook for component documentation&lt;/li&gt;
&lt;li&gt;styled-components for styling&lt;/li&gt;
&lt;li&gt;GitHub Actions for Continuous Integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might be used to or have heard of some of this. Some things might be completely new to you.&lt;/p&gt;

&lt;p&gt;In any case, this tour through the codebase helps you fit the pieces together. I explain the folder structure and the tools used in this project with examples of how they work in action.&lt;/p&gt;

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




&lt;p&gt;&lt;a href="https://profy.dev/article/advanced-react-codebase-tour#nl-5754818q7x3g6" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8f0ippp5y824tz5x10vp.png" alt="Around React Email Course"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>React Coding Challenge Wednesday - Build A Pixel-Perfect Header (Incl Screencast)</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Wed, 07 Sep 2022 10:27:40 +0000</pubDate>
      <link>https://forem.com/profydev/react-coding-challenge-wednesday-build-a-pixel-perfect-header-incl-screencast-4oe5</link>
      <guid>https://forem.com/profydev/react-coding-challenge-wednesday-build-a-pixel-perfect-header-incl-screencast-4oe5</guid>
      <description>&lt;p&gt;&lt;em&gt;Every Wednesday for the next few weeks I'll share a new React coding challenge with increasing difficulty.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Many new developers struggle with CSS. Understandably they rather use UI frameworks. But for a frontend developer working with designs and writing custom CSS is an important skill. Especially when they work on customer-facing products that don't use any of the polished UI libraries. &lt;/p&gt;

&lt;p&gt;So today, let's practice our CSS skills with a simple challenge. This (and all following challenges) are based on &lt;a href="https://github.com/profydev/prolog-app" rel="noopener noreferrer"&gt;this professionally created project on GitHub&lt;/a&gt; and these designs on Figma:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.figma.com/file/wUetHVcyl6e7bSKVkBefXv/React-Job-Simulator---Free-Challenges?node-id=0%3A1" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovc2ie5zgnjgsk7es9yz.png" alt="React Coding Challenges - Figma Designs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge: Make A Header Pixel-Perfect
&lt;/h2&gt;

&lt;p&gt;This challenge is a simple UI task: You build the header component for the application's landing page based on Figma designs. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://prolog.profy.dev/" rel="noopener noreferrer"&gt;Here is the current state of the website&lt;/a&gt; and below is the design.&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%2Fmedia.graphassets.com%2FSlZQya2rQWeOWqP17Y4t" 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%2Fmedia.graphassets.com%2FSlZQya2rQWeOWqP17Y4t" alt="Design Header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Skills tested: CSS&lt;/li&gt;
&lt;li&gt;Difficulty: Easy&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tasks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Implement the header based on the designs.&lt;/li&gt;
&lt;li&gt;The navigation links should point to &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/products&lt;/code&gt;, &lt;code&gt;/documentation&lt;/code&gt;, and &lt;code&gt;/pricing&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The "Open Dashboard" link already exists but needs to be adjusted to match the designs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/profydev/prolog-app" rel="noopener noreferrer"&gt;The repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.figma.com/file/wUetHVcyl6e7bSKVkBefXv/React-Job-Simulator---Free-Challenges?node-id=0%3A1" rel="noopener noreferrer"&gt;The design on Figma.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To run the app on your local machine use the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/profydev/prolog-app.git
&lt;span class="nb"&gt;cd &lt;/span&gt;prolog-app
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hints
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The file you need to edit is &lt;a href="https://github.com/profydev/prolog-app/blob/main/pages/index.jsx" rel="noopener noreferrer"&gt;pages/index.jsx&lt;/a&gt; inside the repository.&lt;/li&gt;
&lt;li&gt;Currently, &lt;a href="https://styled-components.com/" rel="noopener noreferrer"&gt;styled-components&lt;/a&gt; is used for the CSS. I’d recommend using it as well for your code, but alternatively, you can use CSS modules or inline styles. The library doesn’t matter much here.&lt;/li&gt;
&lt;li&gt;The project itself is written in TypeScript but the file for this challenge is plain JSX. Feel free to change the file type to &lt;code&gt;.tsx&lt;/code&gt; if you’re comfortable with that.&lt;/li&gt;
&lt;li&gt;If you need help because you’ve never worked with designs or you want to make them pixel-perfect, you can get additional resources when you drop your email in the form at the bottom of the page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  If you want a tougher challenge you can try to
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Integrate your code into the existing codebase.&lt;/li&gt;
&lt;li&gt;Add a Cypress test for the header to the existing test suite.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Here is the solution to this first task. This is basically what I'd expect a Junior candidate to build for such a challenge (maybe without making the CSS pixel-perfect). All the code is in a single file and not divided into separate components.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Advanced Solution
&lt;/h2&gt;

&lt;p&gt;Here you can watch me refactor the above solution to fit into the existing codebase. It uses the feature-based folder structure, the existing styled-components theme, and adds a Cypress test for the header.&lt;/p&gt;

&lt;p&gt;I wouldn't expect this of a Junior candidate. Especially not in an unknown codebase. Still, it might be interesting to watch.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://profy.dev/coding-challenges-signup?utm_source=rcc-header-1&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqvs91szeuav3loejxhk.png" alt="Signup for access to all challenges, designs &amp;amp; solutions"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Real-World React Coding Challenges For Your Interview Preparation</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Fri, 02 Sep 2022 12:50:41 +0000</pubDate>
      <link>https://forem.com/profydev/real-world-react-coding-challenges-for-your-interview-preparation-22pm</link>
      <guid>https://forem.com/profydev/real-world-react-coding-challenges-for-your-interview-preparation-22pm</guid>
      <description>&lt;p&gt;Working through coding challenges is part of the interview process. Especially if you don’t have a lot of professional experience as a React dev yet. &lt;/p&gt;

&lt;p&gt;But just for these developers coding assignments pose the biggest problem: there are so few job opportunities for entry-level devs that bombing a coding test really hurts. It’s demotivating. Even humiliating.&lt;/p&gt;

&lt;p&gt;So if you’re lucky enough to get a code challenge it’s good to be prepared. And this article is here to help you with that. On this page you can find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4 realistic React coding challenges that test skills like CSS, simple state management, working with API data, and debugging an existing codebase.&lt;/li&gt;
&lt;li&gt;Information about the goal of a coding challenge from an employer’s perspective.&lt;/li&gt;
&lt;li&gt;Tips on how to approach a coding challenge during the interview process.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
React Code Challenges

&lt;ol&gt;
&lt;li&gt;Style A Header Based On Designs&lt;/li&gt;
&lt;li&gt;Toggle A Modal&lt;/li&gt;
&lt;li&gt;Render Elements Based On API Data From A CMS&lt;/li&gt;
&lt;li&gt;Find The Bug&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;The (Lesser Known) Purpose Of Coding Challenges In The Interview Process&lt;/li&gt;
&lt;li&gt;
6 Tips For Coding Challenges In Job Interviews

&lt;ol&gt;
&lt;li&gt;Ask For Clarification&lt;/li&gt;
&lt;li&gt;Talk While You’re Coding (For Live Challenges)&lt;/li&gt;
&lt;li&gt;Clean Code Format&lt;/li&gt;
&lt;li&gt;Use TypeScript And Write Tests If You Can&lt;/li&gt;
&lt;li&gt;Add A README With Clear Instructions&lt;/li&gt;
&lt;li&gt;Be Prepared For Questions&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  React Code Challenges
&lt;/h2&gt;

&lt;p&gt;I recommend you read the whole article before you begin working on the challenges. Nevertheless, let’s start with the most interesting part. Here are a few coding challenges that you could find in a job interview process in your day-to-day work as a developer.&lt;/p&gt;

&lt;p&gt;The challenges are based on the codebase and the designs of the &lt;a href="https://profy.dev" rel="noopener noreferrer"&gt;React Job Simulator&lt;/a&gt;. You can find the &lt;a href="https://github.com/profydev/prolog-app" rel="noopener noreferrer"&gt;source code here on GitHub&lt;/a&gt;. They differ in difficulty and test a variety of skills.&lt;/p&gt;

&lt;p&gt;Let’s start with a simple task.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Style A Header Based On Designs
&lt;/h3&gt;

&lt;p&gt;This challenge is a simple UI task: You build the header component for the application's landing page based on Figma designs. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://prolog.profy.dev/" rel="noopener noreferrer"&gt;Here is the current state of the website&lt;/a&gt; and below is the design.&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%2Fmedia.graphassets.com%2FSlZQya2rQWeOWqP17Y4t" 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%2Fmedia.graphassets.com%2FSlZQya2rQWeOWqP17Y4t" alt="Design Header"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills tested&lt;/strong&gt;: CSS&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Difficulty:&lt;/strong&gt; Easy&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tasks:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement the header based on the designs.&lt;/li&gt;
&lt;li&gt;The navigation links should point to &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;/products&lt;/code&gt;, &lt;code&gt;/documentation&lt;/code&gt;, and &lt;code&gt;/pricing&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The "Open Dashboard" link already exists but needs to be adjusted to match the designs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hints:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The file you need to edit is &lt;a href="https://github.com/profydev/prolog-app/blob/main/pages/index.jsx" rel="noopener noreferrer"&gt;pages/index.jsx&lt;/a&gt; inside the repository.&lt;/li&gt;
&lt;li&gt;Currently, &lt;a href="https://styled-components.com/" rel="noopener noreferrer"&gt;styled-components&lt;/a&gt; is used for the CSS. I’d recommend using it as well for your code, but alternatively, you can use CSS modules or inline styles. The library doesn’t matter much here.&lt;/li&gt;
&lt;li&gt;The project itself is written in TypeScript but the file for this challenge is plain JSX. Feel free to change the file type to &lt;code&gt;.tsx&lt;/code&gt; if you’re comfortable with that.&lt;/li&gt;
&lt;li&gt;If you need help because you’ve never worked with designs or you want to make them pixel-perfect, you can get additional resources when you drop your email below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is the solution to this first task. It's not the cleanest code. I didn't separate the header in a new component file. I didn't use TypeScript or write any tests. But for this challenge it's sufficient.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://profy.dev/article/react-coding-challenges#nl-5760447o6z3a1?utm_source=rcc-1&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kab78r714ww0iovpph8.png" alt="Signup for access to all challenges, designs &amp;amp; solutions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Toggle A Modal
&lt;/h3&gt;

&lt;p&gt;The first challenge was a simple static styling exercise. This one will be a bit more dynamic. &lt;/p&gt;

&lt;p&gt;When a user clicks the contact button in the bottom right corner a modal should open to display some contact information. Again, &lt;a href="https://prolog.profy.dev/" rel="noopener noreferrer"&gt;here is the current state of the website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And here are the designs:&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%2Fmedia.graphassets.com%2FiIyk8a7rQxWSOKvQ0y9i" 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%2Fmedia.graphassets.com%2FiIyk8a7rQxWSOKvQ0y9i" alt="Design contact button"&gt;&lt;/a&gt;&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%2Fmedia.graphassets.com%2FhX7pZV4TTCzO9T32Qi7g" 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%2Fmedia.graphassets.com%2FhX7pZV4TTCzO9T32Qi7g" alt="Design modal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills tested&lt;/strong&gt;: CSS, simple state management, overall React APIs&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Difficulty:&lt;/strong&gt; Easy - Medium&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tasks:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement the modal UI.&lt;/li&gt;
&lt;li&gt;The "Cancel" button should close the modal and the "Open Email App" should open the user's email client.&lt;/li&gt;
&lt;li&gt;The modal should open when the user clicks the contact button.&lt;/li&gt;
&lt;li&gt;Don’t use a modal library.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hints:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The file you need to edit is again &lt;a href="https://github.com/profydev/prolog-app/blob/main/pages/index.jsx" rel="noopener noreferrer"&gt;pages/index.jsx&lt;/a&gt; inside the repository.&lt;/li&gt;
&lt;li&gt;It's OK to add all the code to the file mentioned above.&lt;/li&gt;
&lt;li&gt;There are two ways of implementing the modal: a simple and a more advanced one that not many Juniors know about. Hence one of the skills tested is “overall React APIs”. If you want to see both solutions drop your email in the form below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you want a tougher challenge&lt;/strong&gt; you can try to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrate your code into the existing codebase.&lt;/li&gt;
&lt;li&gt;Add a Cypress test for this challenge to the existing test suite.&lt;/li&gt;
&lt;li&gt;Add a Storybook story for the modal component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately, that’s beyond the scope of this blog post. If you're interested in this check out &lt;a href="https://profy.dev/" rel="noopener noreferrer"&gt;the React Job Simulator&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/react-coding-challenges#nl-5760447o6z3a1?utm_source=rcc-2&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kab78r714ww0iovpph8.png" alt="Signup for access to all challenges, designs &amp;amp; solutions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Render Elements Based On API Data From A CMS
&lt;/h3&gt;

&lt;p&gt;This challenge is a bit more advanced. The goal is to connect our website to a Content Management System (CMS). A CMS is like a database &amp;amp; editor for website content. Good examples are Contentful or Strapi. &lt;/p&gt;

&lt;p&gt;A CMS is often used by marketing departments to easily create content like landing pages or blog posts. The editor enters text, images, and whatever they need. The CMS stores this data and the application (e.g. our website) can access it via an API.&lt;/p&gt;

&lt;p&gt;This way a marketer can easily adjust the text on the website or create completely new pages without asking the developers for help.&lt;/p&gt;

&lt;p&gt;In this challenge, you’ll create the following content element that is controlled by data from an API.&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%2Fmedia.graphassets.com%2FpyzV7ws2QeSbOBDqKgqH" 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%2Fmedia.graphassets.com%2FpyzV7ws2QeSbOBDqKgqH" alt="Design hero section"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills tested&lt;/strong&gt;: Working with API data, CSS&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Difficulty:&lt;/strong&gt; Medium&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tasks:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load data from the endpoint &lt;code&gt;[https://prolog-api.profy.dev/content-page/home](https://prolog-api.profy.dev/content-page/home)&lt;/code&gt; where the last parameter in the URL (&lt;code&gt;home&lt;/code&gt;) is called a "slug" that identifies the page.&lt;/li&gt;
&lt;li&gt;Render the hero section (the part highlighted in the design) based on that data.&lt;/li&gt;
&lt;li&gt;The hero section should match the design.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hints:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can fetch the data however you like.&lt;/li&gt;
&lt;li&gt;It's OK to add all the code to the file &lt;code&gt;pages/index.jsx&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You can &lt;a href="https://prolog-api.profy.dev/api" rel="noopener noreferrer"&gt;find the Swagger documentation for our API here&lt;/a&gt;. (Drop your email below to get more information on that)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;If you want a tougher challenge&lt;/strong&gt; you can try to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Integrate your code into the existing codebase.&lt;/li&gt;
&lt;li&gt;Add a Cypress test for this challenge to the existing test suite.&lt;/li&gt;
&lt;li&gt;Add a Storybook story for the modal component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately, that’s beyond the scope of this blog post. If you're interested in this check out &lt;a href="https://profy.dev/" rel="noopener noreferrer"&gt;the React Job Simulator&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/react-coding-challenges#nl-5760447o6z3a1?utm_source=rcc-3&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kab78r714ww0iovpph8.png" alt="Signup for access to all challenges, designs &amp;amp; solutions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Find The Bug
&lt;/h3&gt;

&lt;p&gt;The previous challenges were all about writing code. This one is a bit different. After all, one of the most important skills of a developer besides building features with code is debugging. So I took a little bug from the &lt;a href="https://profy.dev/" rel="noopener noreferrer"&gt;React Job Simulator&lt;/a&gt; and made it freely available for this challenge.&lt;/p&gt;

&lt;p&gt;When you open the application's &lt;a href="https://prolog.profy.dev/dashboard/issues" rel="noopener noreferrer"&gt;issue page&lt;/a&gt; you can see that either the "Events" or the "Users" column doesn't show the right data.&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%2Fmedia.graphassets.com%2FAo99rQkRTA6jLAOBI1LU" 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%2Fmedia.graphassets.com%2FAo99rQkRTA6jLAOBI1LU" alt="Screenshot issue list bug"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills tested&lt;/strong&gt;: Debugging an existing codebase&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Difficulty:&lt;/strong&gt; Medium&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tasks:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find out what causes the bug.&lt;/li&gt;
&lt;li&gt;Fix it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hints:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Think of a structured approach instead of diving into the codebase heads-first. Rather use your browser’s debugging tools than randomly poking around in the code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/react-coding-challenges#nl-5760447o6z3a1?utm_source=rcc-4&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3kab78r714ww0iovpph8.png" alt="Signup for access to all challenges, designs &amp;amp; solutions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The (Lesser Known) Purpose Of Coding Challenges In The Interview Process
&lt;/h2&gt;

&lt;p&gt;Sure, it's a great idea to practice your skills with as many code challenges as you can. But if you want to pass the interview process it's equally important to understand what an interviewer is looking for.&lt;/p&gt;

&lt;p&gt;No employer wants to buy a pig in a poke. Hiring someone without any proof of their skills is a big risk. Wasted time and money spent on hiring and training. And the emotional burden of having to let someone go.&lt;/p&gt;

&lt;p&gt;One way to test a candidate’s skills is by sending them a coding challenge. This brings its own problems for both sides. But hey, it’s what you often have to deal with if you want the job.&lt;/p&gt;

&lt;p&gt;Obviously, coding challenges test your technical skills (e.g. if you know HTML, CSS, JS, or React).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But many Junior devs focus too much on these technical skills. Keep in mind that your soft skills are a very important factor as well.&lt;/strong&gt; And coding challenges can be a great way to prove that you can communicate or solve problems. An interviewer can ideally follow your thought process and see your attitude towards critique.&lt;/p&gt;

&lt;p&gt;This is especially true for live coding challenges or if the interviewers discuss your take-home assignment in a follow-up interview. So be prepared for questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  6 Tips For Coding Challenges In Job Interviews
&lt;/h2&gt;

&lt;p&gt;Coding challenges can be stressful. Especially if it’s a live assignment where you have to code together with or next to the interviewer.&lt;/p&gt;

&lt;p&gt;Here are a few tips on how to approach them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ask For Clarification
&lt;/h3&gt;

&lt;p&gt;One of the biggest mistakes (especially made by Juniors) is to jump right into the task. Time is limited and you want to spend it coding, right?&lt;/p&gt;

&lt;p&gt;Wrong. The first step of any coding task is to gather all requirements. Re-read the assignment and if you don’t understand something ask for clarification.&lt;/p&gt;

&lt;p&gt;This is not a weakness. Imagine you’re on the job and start building a solution without clearly defining the problem first. You may walk in the wrong direction and possibly waste tons of time. Actually, that happens quite a lot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So for an employer it can be a very important signal if you ask clarifying questions.&lt;/strong&gt; It shows that you have a clear mind and a structured approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Talk While You’re Coding (For Live Challenges)
&lt;/h3&gt;

&lt;p&gt;Live coding challenges can be nerve-wracking. But they are also an opportunity that you don’t have with take-home assignments:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You have a chance to show the interviewer your thought process by talking out loud&lt;/strong&gt; while you write the code. And being able to explain what you’re doing is a great sign for communication skills.&lt;/p&gt;

&lt;p&gt;Unfortunately, that’s easier said than done. Thinking and talking at the same time isn’t for everyone. So practice this upfront. Like &lt;a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging" rel="noopener noreferrer"&gt;rubber duck debugging&lt;/a&gt;. Simply explain what you’re planning to do while you work on a small task. The code challenges earlier on this page are a great opportunity to practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clean Code Format
&lt;/h3&gt;

&lt;p&gt;For many inexperienced developers, a clean code format doesn’t seem to be a big concern. Inconsistencies in indentation, use of semicolons, or variable naming are very common.&lt;/p&gt;

&lt;p&gt;As a Senior developer (aka a potential interviewer) on the other hand, your eyes have practiced seeing these inconsistencies for years. You can spot them right away and they hurt your eyes.&lt;/p&gt;

&lt;p&gt;There’s a simple solution though: &lt;strong&gt;Use a code formatter like Prettier&lt;/strong&gt; for your (take-home) coding assignments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use TypeScript And Write Tests If You Can
&lt;/h3&gt;

&lt;p&gt;Experienced developers appreciate the safety they get from using TypeScript or writing automated tests. So if you’re somewhat comfortable with it use types for your code and add tests. The tool doesn’t matter. You can use Jest, React Testing Library, or Cypress. It doesn’t have to be a lot either. &lt;strong&gt;One or two tests should be enough to show your professionalism.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Add A README With Clear Instructions
&lt;/h3&gt;

&lt;p&gt;Your interviewers probably won’t run your code on their local machine. But if they do you don’t want to leave them confused. &lt;/p&gt;

&lt;p&gt;Add clear instructions on how to install and run your code. And by the way, double-check that your code is working.&lt;/p&gt;

&lt;p&gt;If you have some time left you can also add some additional information to the README. Like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How and why you solved the assignment as you did.&lt;/li&gt;
&lt;li&gt;What assumptions you made.&lt;/li&gt;
&lt;li&gt;What you would improve if you had more time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Be Prepared For Questions
&lt;/h3&gt;

&lt;p&gt;Adding the information described above to your README will also prepare you for the next step: A discussion with your interviewer about your code.&lt;/p&gt;

&lt;p&gt;If you have the chance (e.g. with a take-home test) let the code rest for a bit after you submitted your solution. If you’re invited to a follow-up interview have a close look at your code again. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What seems strange from hindsight?&lt;/li&gt;
&lt;li&gt;Are there parts that are particularly hard to understand?&lt;/li&gt;
&lt;li&gt;How could you improve or refactor your code?&lt;/li&gt;
&lt;li&gt;Anything you would have differently now?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rethinking your code can help you prepare for the next stage of the interview process. After all, it’s very likely that you’ll get questions about your code assignment.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Experienced Programmers Struggle As Well: Ease Your Imposter Syndrome As A Junior Developer</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Fri, 12 Aug 2022 12:13:39 +0000</pubDate>
      <link>https://forem.com/profydev/experienced-programmers-struggle-as-well-ease-your-imposter-syndrome-as-a-junior-developer-36ad</link>
      <guid>https://forem.com/profydev/experienced-programmers-struggle-as-well-ease-your-imposter-syndrome-as-a-junior-developer-36ad</guid>
      <description>&lt;p&gt;At the beginning of their career, most developers feel inadequate. They don’t have anyone to compare themselves to. They don’t know what’s expected of them on the job. And many tutorials or screencasts seem to be created by geniuses.&lt;/p&gt;

&lt;p&gt;All this leads to the all-to-common imposter syndrome among programmers.&lt;/p&gt;

&lt;p&gt;Unfortunately, there’s no easy way around this. Even experienced developers know this feeling of inadequacy. But one of my former team leads suggested how Senior developers can help Junior devs to ease the pain:&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%2Fwt7l3lbhtxfgb5jmxd27.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwt7l3lbhtxfgb5jmxd27.png" alt="Quote Jonathan Stoye"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Part of overcoming imposter syndrome is the understanding that everyone puts on their pants one leg at a time. Watching experienced developers making mistakes, running in the wrong direction, or searching on Google can be very helpful for a Junior developer. &lt;strong&gt;There's no magic. Most developers aren't geniuses.&lt;/strong&gt; And over time, you can get to their level too.&lt;/p&gt;

&lt;p&gt;Obviously, it’s hard to get this pair-programming experience before you find a job with a good and caring team. So I thought I could expose myself a bit here.&lt;/p&gt;

&lt;p&gt;I recorded &lt;a href="https://youtube.com/playlist?list=PLo6qcHP9e9W5T0cwCWsQ4qcoXATqvMzcS" rel="noopener noreferrer"&gt;more than 20 hours of screencasts&lt;/a&gt; of me building a React application as a preparation for my upcoming React Job Simulator. You can see what kind of tools I use including Next.js, TypeScript, Storybook, and GitHub Actions. &lt;strong&gt;But more importantly, you can see that I make mistakes and run into problems all the time&lt;/strong&gt; (despite a decade of professional experience as a developer).&lt;/p&gt;

&lt;p&gt;So let me expose myself. Here are a few takeaways that might ease your imposter syndrome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Things take way longer in reality than in “scripted” videos&lt;/li&gt;
&lt;li&gt;Experienced developers search on Google all the time&lt;/li&gt;
&lt;li&gt;We all struggle with simple problems at times&lt;/li&gt;
&lt;li&gt;Takeaways&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://profy.dev/waitlist" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3o2l1i1322wgkfoc5yl.png" alt="React Job Simulator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Things take way longer in reality than in “scripted” videos
&lt;/h2&gt;

&lt;p&gt;When you watch React videos you might have the impression that developers work super fast. But more often than not these developers have built the application already before. They have run into most issues before and know how to overcome them. &lt;/p&gt;

&lt;p&gt;This makes the videos easy to watch but might skew expectations towards yourself. But let me tell you that reality is often very different. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/JacobraTheGreat/status/1240025611994685441" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FRdwxj6cyQramnQX2mAEH" alt="CleanShot 2022-08-09 at 13.35.34 2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another example: it takes me 10 hours (&lt;a href="https://youtu.be/VSieYssE_vY" rel="noopener noreferrer"&gt;starting with this video&lt;/a&gt;) to build a simple collapsible sidebar navigation. I would have estimated it at 2 hours tops. But again and again, I'm thrown off track because I run into issues with the application and testing setup (e.g. TypeScript, Storybook, Cypress &amp;amp; Jest).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youtu.be/VSieYssE_vY?t=2844" rel="noopener noreferrer"&gt;It takes me more than 20 min to render a simple SVG icon inside my Next.js app and Storybook.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/TOGJ3ALDP4I?t=765" rel="noopener noreferrer"&gt;It takes me 30 min to set up path aliases with TypeScript (and Storybook).&lt;/a&gt; I run into lots of problems and fix them not by a sophisticated debugging approach but by trial and error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From my experience, progressing this slowly is common especially when you create a new project or start working on an existing codebase. At some point when you know how things are done and where they belong your writing code starts to flow more and more. Until you hit the next brick wall of course.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experienced developers search on Google all the time
&lt;/h2&gt;

&lt;p&gt;You might think that Senior developers know it all by heart. They can create a component/context/portal/reducer with one brush and along the way add typings and tests without a second thought.&lt;/p&gt;

&lt;p&gt;But no, even experienced devs can’t remember loads of stuff. You don’t use everything on a daily basis. So you forget things. And sometimes it just doesn’t stick even if you Google it over and over again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/corykelley_/status/1355904924853407749" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2Fi8pw7NFT76EA1wPbDww6" alt="CleanShot 2022-08-09 at 13.13.06.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are a few examples from my screencasts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/S-ZP-mDAhkE?t=7640" rel="noopener noreferrer"&gt;Here I need to look up how React context works&lt;/a&gt;. I don’t use it that often so I just forget. Instead of Googling I also like to simply copy &amp;amp; paste from another file in the project.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/b38W9mErikA?t=1726" rel="noopener noreferrer"&gt;Here I’m stuck on a simple TypeScript configuration problem.&lt;/a&gt; The solution was actually simple (just disable the &lt;code&gt;isolatedModules&lt;/code&gt; flag in the &lt;code&gt;tsconfig&lt;/code&gt; file). But I couldn’t see the forest for the trees. Instead of simply looking at the docs (one of the top results on Google) I randomly open tutorials and StackOverflow questions only to settle on a hacky workaround.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  We all struggle with simple problems at times
&lt;/h2&gt;

&lt;p&gt;You might think: “Sure also experienced developers struggle. But the problems they struggle with are much tougher!”&lt;/p&gt;

&lt;p&gt;And yeah, that’s true. But even with years of experience, you’ll have a sufficient number of face-palm moments. You might work on something for days only to find out that you built an inferior version of an existing npm package. You might Google for hours for a solution to your broken CSS only to find out you forgot to import the stylesheet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/pokecoder/status/1461564847246565379" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.graphassets.com%2FOqXo4QkwTTqcoKWxtRbx" alt="CleanShot 2022-08-09 at 13.27.12.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are a few examples of my screencasts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/S-ZP-mDAhkE?t=5940" rel="noopener noreferrer"&gt;Here I’m surprised that an element is wider than in the designs.&lt;/a&gt; I settle on a weird workaround using CSS &lt;code&gt;calc(width - padding)&lt;/code&gt; only to find this comment later:&lt;/li&gt;
&lt;/ul&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%2Fmedia.graphassets.com%2F9llyxdYSSEOuUWJEgzOq" 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%2Fmedia.graphassets.com%2F9llyxdYSSEOuUWJEgzOq" alt="Why not use box-sizing?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/S-ZP-mDAhkE?t=7502" rel="noopener noreferrer"&gt;Here I’m wondering what’s the best approach to keeping a navigation bar collapsed while navigating to another route.&lt;/a&gt; It takes me a while to understand that I need to switch from local state to global state with context.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;p&gt;Hopefully, these examples were enough to convince you that (most) developers are only humans. But obviously, there are also lots of things that you learn over time. Here is a short list of some of the most important things I do differently now compared to myself early in my career:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read error messages carefully. Often the solution to your problem lies within.&lt;/li&gt;
&lt;li&gt;Google is your friend but use the docs as a starting point instead of searching for tutorials right away.&lt;/li&gt;
&lt;li&gt;If you get stuck take a step away, go for a walk, take a nap, or do whatever you like. The solution to your problem often comes while your brain rests.&lt;/li&gt;
&lt;li&gt;Review your own code after taking some time off. You gain a new perspective on your code and can detect problems easier.&lt;/li&gt;
&lt;li&gt;Debug problems systematically and not by changing random code all over the place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://profy.dev/waitlist" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc3o2l1i1322wgkfoc5yl.png" alt="React Job Simulator"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How Professional (React) Developer Teams Plan &amp; Estimate Features (incl screencast)</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Fri, 01 Apr 2022 12:41:07 +0000</pubDate>
      <link>https://forem.com/profydev/how-professional-react-developer-teams-plan-estimate-features-incl-screencast-1c9m</link>
      <guid>https://forem.com/profydev/how-professional-react-developer-teams-plan-estimate-features-incl-screencast-1c9m</guid>
      <description>&lt;p&gt;To plan their features professional teams use processes with multiple roles involved. They ideate, design, plan, estimate, and prioritize features before they start the implementation. They split large features into small chunks that can be tackled by multiple devs in parallel.&lt;/p&gt;

&lt;p&gt;Sounds reasonable. But without job experience, you probably don’t have a clue what that looks like in real life. &lt;strong&gt;The goal of this article is to expose you to a typical feature planning process. One that you’ll likely encounter on your first job.&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, we’ll cover a bit of theory about a typical product team and the planning process.&lt;/li&gt;
&lt;li&gt;Later we’ll apply the learnings to two examples. At least the parts that you’ll likely be involved in as a Junior developer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The examples are based on user stories and designs. &lt;strong&gt;This way you can see the process applied in a realistic scenario and practice it yourself.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My advice is to read at least the theory part on this page before watching the video below. The explanations here are admittedly better than in the video.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to get hands-on practice in a professional environment &lt;a href="https://profy.dev/waitlist?utm_source=fp-1&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;sign up for the upcoming React Job Simulator&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A Typical Product Team&lt;/li&gt;
&lt;li&gt;
The Feature Planning Process

&lt;ul&gt;
&lt;li&gt;Feature Requests, Stories &amp;amp; Designs&lt;/li&gt;
&lt;li&gt;Refinement&lt;/li&gt;
&lt;li&gt;Estimations&lt;/li&gt;
&lt;li&gt;Technical Planning&lt;/li&gt;
&lt;li&gt;Implementation, QA &amp;amp; Deployment&lt;/li&gt;
&lt;li&gt;The Board&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Example 1: Planning a simple Sidebar Navigation

&lt;ul&gt;
&lt;li&gt;User Story&lt;/li&gt;
&lt;li&gt;Refinement&lt;/li&gt;
&lt;li&gt;Estimation&lt;/li&gt;
&lt;li&gt;Technical Planning&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Example 2: Planning a complex interactive page

&lt;ul&gt;
&lt;li&gt;User Story&lt;/li&gt;
&lt;li&gt;Refinement&lt;/li&gt;
&lt;li&gt;Estimation&lt;/li&gt;
&lt;li&gt;Technical Planning&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The descriptions here are based on my experience working with a handful of teams. The exact process and responsibilities differ from team to team. But the overall picture should be similar in many companies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A Typical Product Team
&lt;/h2&gt;

&lt;p&gt;Before we dive into the planning process we should understand what a typical product team looks like. What kind of roles are involved? What are their responsibilities?&lt;/p&gt;

&lt;p&gt;These are the people that a frontend developer works with on a daily basis:&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%2Fmedia.graphcms.com%2FahqTcM5TRCSkXFQA8IqA" 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%2Fmedia.graphcms.com%2FahqTcM5TRCSkXFQA8IqA" alt="typical-product-team"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: this is written from the perspective of a developer. Some things are simplified and technically not accurate (e.g. Product Manager and Product Owner may not be the same role). There might also be other roles involved like QA engineers. Still this should paint a similar picture to what a new developer encounters in their first job.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The Product Manager&lt;/strong&gt; (or Product Owner in Scrum terminology): there’s typically one PM for a team of developers. They basically ensure that the devs have something to work on (apart from refactoring the codebase).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They gather feature requests and requirements.&lt;/li&gt;
&lt;li&gt;They write tasks in the form of user stories (more on that later).&lt;/li&gt;
&lt;li&gt;They prioritize features and tasks together with upper management.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In essence, Product Managers are the bridge between the outer world (e.g. upper management or other departments) and the developers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Designer:&lt;/strong&gt; there’s typically one designer for a team of developers. Often they even work with multiple teams. Their responsibilities are creating UI designs (obviously) but they might also be involved in user research (e.g. as UX designers).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Developers:&lt;/strong&gt; for every Product Manager or Designer there are typically multiple developers. In most cases, the development is the bottleneck of building a product. Their responsibility is to implement new features, fix bugs, maintain and improve the system, but also to participate in plannings and estimations of upcoming features.&lt;/p&gt;

&lt;p&gt;Which leads us to the next chapter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Feature Planning Process
&lt;/h2&gt;

&lt;p&gt;Here is a bit of background information about how a feature makes its way from ideation to being deployed to production. This is a bit theoretical but we’ll see two hands-on examples later on.&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%2Fmedia.graphcms.com%2FatjQl5R1TZqAf4u9vSpU" 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%2Fmedia.graphcms.com%2FatjQl5R1TZqAf4u9vSpU" alt="feature-lifecycle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Feature Requests, Stories &amp;amp; Designs
&lt;/h3&gt;

&lt;p&gt;The whole process starts with a request for a new feature. This request might come from within the team, the business people, another department (like the marketing department), or the company’s users.&lt;/p&gt;

&lt;p&gt;The Product Manager gathers the requirements for the feature, works with the designer to create the UI, and writes user stories. Often one or more developers are also involved in this process to understand technical feasibility early on.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;User Story&lt;/strong&gt; is a type of task that describes (part of a) feature from the perspective of a user. It doesn’t contain much technical information but explains the purpose of the ticket. Multiple stories might be grouped together as an &lt;strong&gt;Epic&lt;/strong&gt; which describes the complete feature. &lt;/p&gt;

&lt;p&gt;A common template for a user story is this: “As a ... I want ... so that ...”&lt;/p&gt;

&lt;p&gt;An example: “&lt;strong&gt;As a&lt;/strong&gt; user &lt;strong&gt;I want&lt;/strong&gt; to use a navigation bar &lt;strong&gt;so that&lt;/strong&gt; I can easily visit all the important parts of the application”. &lt;/p&gt;

&lt;h3&gt;
  
  
  Refinement
&lt;/h3&gt;

&lt;p&gt;Once the Product Manager decides that the feature and user stories are in a presentable state they discuss them with the developers in a so-called &lt;strong&gt;backlog refinement or backlog grooming&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is a meeting where the whole team meets and everyone has a chance to ask questions and raise concerns about potential implementation issues. For example, a part of the feature might look simple but could be very complicated to implement. Often the PM and designer aren’t aware of that. The team can discuss the issue and either find a simpler solution or split the story into smaller chunks.&lt;/p&gt;

&lt;p&gt;Once all questions are cleared it’s time to estimate the effort.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estimations
&lt;/h3&gt;

&lt;p&gt;Management needs to make projections. When will a feature be ready? When should our customers expect it? What does our roadmap look like? Usually, estimations are used to make these projections. And the easiest and most obvious way to estimate is to ask a developer: “How long does it take to build this?”&lt;/p&gt;

&lt;p&gt;Nothing a developer hates more...&lt;/p&gt;

&lt;p&gt;Experience shows, that this leads to vastly underestimated timelines. So smart people tried to decouple estimates from time by assigning complexity points to stories. Developers basically say: “This task sounds complicated. I give it an 8.” or “This is simple. It’s a 1”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;These numbers are called Storypoints.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;They don’t have any inherent meaning but over time the team usually aligns on what each number represents.&lt;/p&gt;

&lt;p&gt;The idea is that you can observe how many points a team can accomplish in a certain timeframe (often a 2-week Sprint). This is called velocity. And the average velocity over a couple of Sprints can then be used by management to get a time estimate for a feature.&lt;/p&gt;

&lt;p&gt;Many teams use numbers from the Fibonacci series (1, 2, 3, 5, 8, 13, 21...). The theory is that the more complex a task the more inaccurate its estimate. The increasing gaps between the Storypoints represent this inaccuracy.&lt;/p&gt;

&lt;p&gt;Now, this sounds all great in theory. But the numeric nature of Storypoints often leads to misuse. Typical signs are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Storypoint estimate is transformed into a time estimate. Example: “This story has 1 point so it should take half a day.”&lt;/li&gt;
&lt;li&gt;Storypoint estimates are turned against the dev team: “You gave this feature 60 points in total so you have a deadline of 4 weeks” or “This team needs to increase its velocity.” or worse “Team A is much more performant than Team B because of its higher velocity.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most importantly though, &lt;a href="https://youtu.be/QVBlnCTu9Ms?t=1585" rel="noopener noreferrer"&gt;research shows that you can simply count the number of stories instead of the Storypoints and basically get the same estimate&lt;/a&gt;. So the whole estimation effort might be a waste of time.&lt;/p&gt;

&lt;p&gt;Nevertheless, most teams make use of Storypoint estimations. So if you want to start a career as a developer you’re likely to encounter them sooner rather than later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Planning
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;This meeting is optional. It might also take place before the estimations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once the user stories are estimated the developers gather again to discuss the technical details. Remember, a user story is written from the user’s perspective and typically doesn’t contain a lot of technical information.&lt;/p&gt;

&lt;p&gt;Much of the technical discussion should already have happened before the estimation. So if required the devs simply break each user story into multiple technical tasks that make sense from their perspective. These could include things like adding a column to a Database table, updating the API, or adding a component to the UI library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation, QA &amp;amp; Deployment
&lt;/h3&gt;

&lt;p&gt;At this point, the user stories are ready for development. The developers pick them up one by one and implement them. Somebody tests the implementation. Ideally, the feature is covered with automated tests to prevent future regressions. And finally, the feature is deployed to production so the users can benefit from it.&lt;/p&gt;

&lt;p&gt;We won’t go into details here since this article focuses on the planning process.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Board
&lt;/h3&gt;

&lt;p&gt;All the tasks are visualized on a board. Below is an example of a Kanban-style board with multiple columns. The user stories start at the very left in the backlog. Once they are refined and estimated they can be moved to the Todo column. Now developers can pick a task and move it to the next columns depending on its implementation status.&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%2Fmedia.graphcms.com%2FtKK0I6LmThOI25wuUsgM" 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%2Fmedia.graphcms.com%2FtKK0I6LmThOI25wuUsgM" alt="kanban-board"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/waitlist?utm_source=fp-2&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7axx4l91vzamfzjpa5f5.png" alt="React Job Simulator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 1: Planning a simple Sidebar Navigation
&lt;/h2&gt;

&lt;p&gt;All this theory can be a bit boring and hard to understand. So let’s continue with two hands-on examples. We’ll start with a simple component.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I don't usually suggest to view the blog on my website. But if you want to practice the process you will have a better experience there since the solutions are hidden initially. &lt;a href="https://profy.dev/article/feature-planning#example-1-planning-a-simple-sidebar-navigation" rel="noopener noreferrer"&gt;Click here to jump to this section on my website.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  User Story
&lt;/h3&gt;

&lt;p&gt;The first user story of the &lt;a href="https://profy.dev/waitlist" rel="noopener noreferrer"&gt;upcoming React Job Simulator&lt;/a&gt; is the sidebar navigation. Here is a screenshot of the ticket from the board above:&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%2Fmedia.graphcms.com%2FjgrDhph0TkSpdkiWcqZw" 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%2Fmedia.graphcms.com%2FjgrDhph0TkSpdkiWcqZw" alt="user-story-navigation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the actual User Story, the design, and a list of Acceptance Criteria (also AC). The exact ticket format varies from team to team. The AC don’t include many technical details but describe the functionality from the perspective of a user. Here they basically describe the behavior of the design in words.&lt;/p&gt;

&lt;h3&gt;
  
  
  Refinement
&lt;/h3&gt;

&lt;p&gt;During the refinement session, the team goes through the User Story, the design, and the proposed Acceptance Criteria.&lt;/p&gt;

&lt;p&gt;Please have a look yourself. Are there inconsistencies in the design? Anything unclear from the ticket description? Anything wrong or missing from the AC? Anything you’d like to change?&lt;/p&gt;

&lt;p&gt;Here is what I found:&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;The refinement of this ticket reveals two smaller problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The last acceptance criterion contains a mistake: the navigation bar shouldn’t slide out to the right but to the left.&lt;/li&gt;
&lt;li&gt;The current page is highlighted in the menu (the “Issues” page in the design). This is missing from the acceptance criteria.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Product Manager agrees and updates the AC:&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%2Fmedia.graphcms.com%2FOUYYI6PdRfG2jAdxNMEi" 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%2Fmedia.graphcms.com%2FOUYYI6PdRfG2jAdxNMEi" alt="navigation-updated-acceptance-criteria"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Estimation
&lt;/h3&gt;

&lt;p&gt;The user story is pretty clear so we move on to estimate the user story. As a reminder, every developer picks a number of the Fibonacci series (1, 2, 3, 5, 8, 13, 21) where 1 is a very simple task. Let’s say changing a text or color could be a 1.&lt;/p&gt;

&lt;p&gt;Here is a chance for you to practice: Think of a number that represents the complexity of this user story before you read on. No worries, there’s no right or wrong at this point.&lt;/p&gt;

&lt;p&gt;My estimate and explanation:&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As I said, there’s no right or wrong in this answer. Over time our understanding of these estimates would more and more align.&lt;/p&gt;

&lt;p&gt;Assuming that you said something different we could agree on one of the estimates (often the higher one just to be safe). Or we discuss our reasons. This can be very valuable when there are big differences in estimates because it often shows a need for clarification of the user story.&lt;/p&gt;

&lt;p&gt;So let me explain why I picked a 3: The sidebar navigation doesn’t look overly complex. It’s a simple UI component without API calls or so involved. But there is a bit of interactivity: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The sidebar on desktop is collapsible so we need some kind of state.&lt;/li&gt;
&lt;li&gt;The current element is highlighted. This shouldn’t be hard using the URL but it adds some complexity.&lt;/li&gt;
&lt;li&gt;The mobile design behaves differently from the desktop version.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Planning
&lt;/h3&gt;

&lt;p&gt;From my perspective, we don’t need to split this user story into multiple technical tasks. We might create a task each for desktop and mobile design due to the different behavior. But I’d leave it as a single user story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example 2: Planning a complex interactive page
&lt;/h2&gt;

&lt;p&gt;The sidebar navigation was pretty straightforward. Now let’s have a look at a more complex user story from my &lt;a href="https://profy.dev/waitlist" rel="noopener noreferrer"&gt;upcoming React Job Simulator&lt;/a&gt;. Here is a screenshot of the issues page design:&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%2Fmedia.graphcms.com%2FjqLHPA8TokpI2TuU6UzA" 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%2Fmedia.graphcms.com%2FjqLHPA8TokpI2TuU6UzA" alt="issues-page-design"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alright, there are a lot more complex components and interactive elements in this design. A look at the board shows that the Product Manager created two user stories:&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%2Fmedia.graphcms.com%2FwqcR2znsQPu1EkeYN8nm" 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%2Fmedia.graphcms.com%2FwqcR2znsQPu1EkeYN8nm" alt="issues-page-stories"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s take the “Issue List” as an example here.&lt;/p&gt;

&lt;h3&gt;
  
  
  User Story
&lt;/h3&gt;

&lt;p&gt;Here is a screenshot of the user story:&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%2Fmedia.graphcms.com%2FRReEL8tnQ36eK0iyrHWh" 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%2Fmedia.graphcms.com%2FRReEL8tnQ36eK0iyrHWh" alt="issue-list-user-story"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Refinement
&lt;/h3&gt;

&lt;p&gt;Again, please have a look yourself. Are there inconsistencies in the design? Anything unclear from the ticket description? Anything wrong or missing from the AC? Anything you’d like to change?&lt;/p&gt;

&lt;p&gt;Here is what I found:&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;You can see the complexity of this user story from the acceptance criteria alone. When we have a closer look there are a few things to note:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The name of the column “Level” in the original design is “Status” in the user story. The design in the user story is just a screenshot of the real design in Figma. And it seems outdated. So never rely on the screenshots in the description of a task.&lt;/li&gt;
&lt;li&gt;The pagination buttons don’t behave as expected in the design. On the first page, the “Previous” button should be disabled. On the last page, the “Next” button should be disabled. This should also be reflected in the AC.&lt;/li&gt;
&lt;li&gt;A large chunk of the acceptance criteria is about the checkboxes and the related “Resolve selected issues” button on top of the table. While it might make sense to include this in the story from the Product Manager’s perspective, we as developers know that there’s a lot going on behind the scenes. The behavior of the checkboxes is already somewhat complex. And a click on the button triggers an API request which includes error handling and the update of the issue list. The suggestion here is to move this to a separate user story “Resolve Issues”.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Luckily, the Product Manager doesn’t put up a fight. They create a separate user story (we’ll ignore that here) and update the AC according to our feedback:&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%2Fmedia.graphcms.com%2F6LvRTW2yRyqYtaixuia6" 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%2Fmedia.graphcms.com%2F6LvRTW2yRyqYtaixuia6" alt="issue-list-update-acceptance-criteria"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the refinement session helped to keep the user story concise and uncovered some cases that weren’t yet mentioned in the acceptance criteria. Especially getting the input of multiple developers can be illuminating here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estimation
&lt;/h3&gt;

&lt;p&gt;It’s time for the estimation. Pick a Storypoint (1, 2, 3, 5, 8, 13, or 21) where 1 is a simple task like changing a text or color.&lt;/p&gt;

&lt;p&gt;Here is mine:&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Again, it’s expected that we picked different Storypoints. No right or wrong here. But let me explain my decision:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The table row itself is pretty straightforward (assuming that we get a list of issues with the required data). But the graph could become a bit more complex. We probably should use a chart library and need to compare different options. There’s always a risk that the library doesn’t really fit all requirements like the rounded bars or the gap between bars.&lt;/li&gt;
&lt;li&gt;The pagination adds some complexity. I’m assuming here that the API supports proper pagination. In any case, we need to trigger new API calls whenever one of the buttons is clicked and handle the state of the buttons according to the current page.&lt;/li&gt;
&lt;li&gt;Remember the original design? On desktop, we have a table. On mobile, each issue is rendered as a card though. I’m not sure how complicated this will be from the top of my head. I guess it should be possible with a CSS grid or so. Still, from my perspective, this adds to the story’s complexity.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Technical Planning
&lt;/h3&gt;

&lt;p&gt;This user story is obviously a bit more complex. I’d say it makes sense to split it into multiple tasks for the developers. There are some advantages to having multiple smaller tasks: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Pull Requests don’t become that big and thus are easier to review.&lt;/li&gt;
&lt;li&gt;Multiple developers can start implementing the feature in parallel (if the tasks don’t depend on each other too much).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So let’s start breaking the user story up. As a reminder here are the design and the acceptance criteria from the story:&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%2Fmedia.graphcms.com%2FHuxD15ThOuMBMhpmZ6GA" 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%2Fmedia.graphcms.com%2FHuxD15ThOuMBMhpmZ6GA" alt="issue-list-design"&gt;&lt;/a&gt;&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%2Fmedia.graphcms.com%2F6LvRTW2yRyqYtaixuia6" 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%2Fmedia.graphcms.com%2F6LvRTW2yRyqYtaixuia6" alt="issue-list-update-acceptance-criteria"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Think about the different tasks that you would create. How can you split the story into small self-contained tasks? How can you allow multiple devs to work in parallel?&lt;/p&gt;

&lt;p&gt;Here are the tasks that I created&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;...&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%2Fmedia.graphcms.com%2Fm7gkD73Q0qrQadzyqKxD" 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%2Fmedia.graphcms.com%2Fm7gkD73Q0qrQadzyqKxD" alt="issue-list-technical-tasks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The “Create Issue Row” task is a simple UI component excluding the graph. We can build this with the help of Storybook. This should be tackled first.&lt;/li&gt;
&lt;li&gt;The “Create Table Task” contains the API call and rendering of the items in a table. It depends on the “Create Issue Row” task but a developer could start already to implement the API call.&lt;/li&gt;
&lt;li&gt;The “Create Mobile Design” task can be started as soon as the first task is done. I’m honestly not sure if this should be a separate task or not. Making this a separate task could lead the developer to forget about the differences between the desktop and mobile design. But that would make a great exercise for the React Job Simulator.&lt;/li&gt;
&lt;li&gt;The “Implement Pagination” task can be started as soon as the “Create Issue Table” task is done. It’s very independent of the other tasks otherwise.&lt;/li&gt;
&lt;li&gt;Finally, the “Create Graph” task is about the column showing the graph. Since this adds a bit of complexity to the user story it makes sense to extract it into a separate task. This way the Product Manager can de-prioritize the graph if there’s a pressing deadline or the team concludes that the effort is not justifiable at this moment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://profy.dev/waitlist?utm_source=fp-3&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7axx4l91vzamfzjpa5f5.png" alt="React Job Simulator"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Continuous Integration Pipelines with GitHub Actions for (React) Developers (incl screencast)</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Sat, 19 Mar 2022 12:18:12 +0000</pubDate>
      <link>https://forem.com/profydev/continuous-integration-pipelines-with-github-actions-for-react-developers-incl-screencast-467</link>
      <guid>https://forem.com/profydev/continuous-integration-pipelines-with-github-actions-for-react-developers-incl-screencast-467</guid>
      <description>&lt;p&gt;If you don’t have experience working with a professional dev team yet, you probably don’t know how collaboration among developers typically works. One of the most important parts is the Git workflow. &lt;/p&gt;

&lt;p&gt;A very common workflow among professional teams is Trunk-Based Development. In a nutshell, it works like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You work on a separate Git branch and push it to GitHub.&lt;/li&gt;
&lt;li&gt;You create a Pull Request where automated scripts check your code and your teammates review it.&lt;/li&gt;
&lt;li&gt;You merge the Pull Request to the main branch once it’s approved.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We covered this workflow in detail in a &lt;a href="https://profy.dev/article/trunk-based-development-with-github" rel="noopener noreferrer"&gt;previous article&lt;/a&gt;. So if anything is unclear, I’d recommend reading it first (or have a look at &lt;a href="https://profy.dev/project/github-minesweeper" rel="noopener noreferrer"&gt;my free course where you can learn and practice this workflow&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;On this page, we’ll focus on the automated scripts in the second step. This is called the Continuous Integration pipeline and typically runs tools like a linter (e.g. ESLint), code formatter (e.g. Prettier), or tests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If this is all sounds like Gibberish, no worries. Have a look at &lt;a href="https://profy.dev/project/github-minesweeper" rel="noopener noreferrer"&gt;my free course where you can learn and practice this workflow&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the video below I walk through the setup of a GitHub repository for a Next.js app that I created in a &lt;a href="https://profy.dev/article/setup-react-project" rel="noopener noreferrer"&gt;previous blog post&lt;/a&gt;. You can find a summary below the video. In a nutshell, you’ll learn&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to set up a Continuous Integration pipeline with GitHub Actions to automatically run ESLint, Prettier, and tests in each Pull Request.&lt;/li&gt;
&lt;li&gt;How to prevent code from being merged to the main branch if it doesn’t pass the pipeline.&lt;/li&gt;
&lt;li&gt;How to use pre-commit hooks to run checks even before you can create a commit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application is part of the &lt;a href="https://profy.dev/waitlist" rel="noopener noreferrer"&gt;upcoming React Job Simulator&lt;/a&gt; where you can work on an existing codebase using this and other professional workflows and tools. Just like you would in a real job.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Continuous Integration with GitHub Actions&lt;/li&gt;
&lt;li&gt;Status Checks: Prevent merges of Pull Requests that don’t pass the CI pipeline&lt;/li&gt;
&lt;li&gt;Pre-commit hooks: validate your code before a commit&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Continuous Integration with GitHub Actions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://profy.dev/article/trunk-based-development-with-github#branch-protection-enforce-usage-of-pull-requests" rel="noopener noreferrer"&gt;In the previous article, we set up the GitHub repository to use branch protection&lt;/a&gt;. This way we can enforce branches can only be merged to the main branch via a Pull Request that is approved by another teammate.&lt;/p&gt;

&lt;p&gt;The approval process can be very valuable. But especially code reviews are also time-consuming. You don’t want to waste time complaining about details like code formatting. On top of that, it’s not feasible to test all the code by hand to ensure that the rest of the application still works as expected.&lt;/p&gt;

&lt;p&gt;As you know, we have tools to assist us: TypeScript and ESLint to catch bugs, Prettier to format our code, and tests to make sure that our app works. &lt;/p&gt;

&lt;p&gt;With the help of a Continuous Integration pipeline, we can run all these tools within our Pull Requests. This way we decrease the effort spent on code reviews and reduce the risk of introducing bugs. And that again helps to merge Pull Requests frequently (&lt;a href="https://en.wikipedia.org/wiki/Continuous_integration" rel="noopener noreferrer"&gt;which is the whole meaning of Continuous Integration by the way&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;There are many tools to build CI pipelines. The simplest option for repositories on GitHub is probably GitHub Actions. It’s as easy as creating a file called  &lt;code&gt;.github/workflows/main.yml&lt;/code&gt; in your repo. &lt;/p&gt;

&lt;p&gt;For my project, the file looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# runs on pushes to the main branch&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;# also runs inside pull requests that target the main branch&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# uses a Ubuntu Docker image (like a virtual machine)&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;14"&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npm"&lt;/span&gt;
      &lt;span class="c1"&gt;# install dependencies&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="c1"&gt;# run ESLint &amp;amp; Prettier&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run lint&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run prettier&lt;/span&gt;
      &lt;span class="c1"&gt;# verify that there are no build errors&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
      &lt;span class="c1"&gt;# run tests with Cypress&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cypress run&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cypress-io/github-action@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following happens whenever a commit is pushed to the main branch or to a pull request that targets the main branch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Ubuntu machine is spun up, the code from the repo checked out, and Node.js installed.&lt;/li&gt;
&lt;li&gt;ESLint and Prettier are run to check for bugs and correct code format.&lt;/li&gt;
&lt;li&gt;The project is built to verify that there are no TypeScript and build errors.&lt;/li&gt;
&lt;li&gt;The Cypress tests are run to verify that the app behaves as expected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our Pull Request, we now have status checks (one to be precise).&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%2Fmedia.graphcms.com%2F2NjqqVu4SxW6ygqexTBD" 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%2Fmedia.graphcms.com%2F2NjqqVu4SxW6ygqexTBD" alt="Pull Request - CI status check"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case something goes wrong and the CI pipeline fails we can inspect the details. You just click on the “Details” link at the very right of the status check. &lt;/p&gt;

&lt;p&gt;Here is an example where I committed code that wasn’t formatted correctly. This looks just like the output of a normal terminal. &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%2Fmedia.graphcms.com%2Fb3TzQrUZRISR2VDvXgVX" 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%2Fmedia.graphcms.com%2Fb3TzQrUZRISR2VDvXgVX" alt="CI details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Status Checks: Prevent merges of Pull Requests that don’t pass the CI pipeline
&lt;/h2&gt;

&lt;p&gt;At this point, we force everyone on the team to use Pull Requests and we have a CI pipeline that automatically checks our code. Unfortunately, a developer can still decide to merge a PR even though it didn’t pass the CI pipeline. Wouldn’t it be awesome if we could prevent that?&lt;/p&gt;

&lt;p&gt;That’s where our &lt;a href="https://profy.dev/article/trunk-based-development-with-github#branch-protection-enforce-usage-of-pull-requests" rel="noopener noreferrer"&gt;branch protection rules from the previous article&lt;/a&gt; come in again. You can find an option “Require status checks to pass before merging” that we didn’t select before. Once our CI pipeline has run at least one time we can enable it and select the required CI jobs.&lt;/p&gt;

&lt;p&gt;You simply edit the existing rules for the main branch, check the option, and select the job from the workflow file (in this case “build”).&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%2Fmedia.graphcms.com%2FB4Jgik3ShyhbButlhTq3" 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%2Fmedia.graphcms.com%2FB4Jgik3ShyhbButlhTq3" alt="require status checks in branch protection rules"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the merge button inside a Pull Request is disabled whenever the CI pipeline fails.&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%2Fmedia.graphcms.com%2FdkS6Pil1QCYKeK76IiLA" 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%2Fmedia.graphcms.com%2FdkS6Pil1QCYKeK76IiLA" alt="pull request - merge button disabled when ci fails"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-commit hooks: validate your code before a commit
&lt;/h2&gt;

&lt;p&gt;Once you start working with CI pipelines you realize that it takes a while to run them. It can be annoying to come back to a Pull Request after a few minutes only to realize that the CI failed because of a dumb ESLint error.&lt;/p&gt;

&lt;p&gt;This is where pre-commit hooks come in handy. They allow you to automatically run scripts when you create a commit. If one of the scripts fails the commit is stopped. &lt;/p&gt;

&lt;p&gt;Since the goal is to commit frequently I wouldn’t recommend running complex tasks in pre-commit hooks. For example, running a whole test suite on every commit quickly gets annoying. Pre-commit hooks are best suited for fast scripts like &lt;code&gt;npm run lint&lt;/code&gt; or &lt;code&gt;npm run prettier&lt;/code&gt;. Especially when they only check the staged files and not the whole repository.&lt;/p&gt;

&lt;p&gt;The easiest way to set up pre-commit hooks that only run on staged files is by using &lt;a href="https://github.com/okonet/lint-staged" rel="noopener noreferrer"&gt;lint-staged&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;npx mrm@2 lint-staged&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install &lt;a href="https://github.com/typicode/husky" rel="noopener noreferrer"&gt;Husky&lt;/a&gt; under the hood and set up some scripts to run before a commit. You can find them in the &lt;code&gt;lint-staged&lt;/code&gt; section in your &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;This is the &lt;code&gt;package.json&lt;/code&gt; file for my project. I already adapted it to run on JavaScript and TypeScript files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scripts"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;...&lt;/span&gt; &lt;span class="pi"&gt;},&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dependencies"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;...&lt;/span&gt; &lt;span class="pi"&gt;},&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;devDependencies"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;...&lt;/span&gt; &lt;span class="pi"&gt;},&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lint-staged"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*.{js,jsx,ts,tsx}"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eslint&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--cache&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--fix"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*.{js,jsx,ts,tsx,css,md}"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prettier&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--write"&lt;/span&gt;
  &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="pi"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you try to commit code that contains an ESLint error the pre-commit hook will complain now.&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%2Fmedia.graphcms.com%2Fg9SbtHdASPqy4ItwBmau" 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%2Fmedia.graphcms.com%2Fg9SbtHdASPqy4ItwBmau" alt="pre-commit hooks with husky prevent a commit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that it’s easy to skip the pre-commit hooks by using the &lt;code&gt;git commit --no-verify&lt;/code&gt; option. So you can compare our setup to form validation in web apps: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The pre-commit hooks are the validation on the frontend. They give quick feedback but you can easily hack them.&lt;/li&gt;
&lt;li&gt;The CI pipeline is the backend validation: It takes a bit longer to realize that something went wrong but you can’t simply work around them.&lt;/li&gt;
&lt;/ul&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%2Fc7ijm8eibvnde1i5d6b9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc7ijm8eibvnde1i5d6b9.png" alt="Bootcamp for Self-Taught React devs"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>github</category>
      <category>devops</category>
    </item>
    <item>
      <title>Professional Git Workflow &amp; GitHub Setup for (React) Developers (incl screencast)</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Fri, 18 Mar 2022 12:31:58 +0000</pubDate>
      <link>https://forem.com/profydev/professional-git-workflow-github-setup-for-react-developers-pfj</link>
      <guid>https://forem.com/profydev/professional-git-workflow-github-setup-for-react-developers-pfj</guid>
      <description>&lt;p&gt;If you’re a solo developer working on your own projects your Git workflow is usually simple: You work on the main (or master) branch all day every day.&lt;/p&gt;

&lt;p&gt;You probably know that professional developer teams don't work like this. Multiple devs all committing to the main branch can quickly become chaotic. And it’s likely that unreviewed or untested code makes it into production eventually. Danger!&lt;/p&gt;

&lt;p&gt;Professional teams use processes and workflows to prevent this from happening. And the most common Git workflow used in developer teams (at least from my experience):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trunkbaseddevelopment.com/#scaled-trunk-based-development" rel="noopener noreferrer"&gt;Trunk-Based Development&lt;/a&gt; (or more correctly Scaled Trunk-Based Development).&lt;/p&gt;

&lt;p&gt;If your goal is to find a job as a professional developer I highly recommend getting used to this workflow upfront. The more you know how to work like a professional the less you’ll be overwhelmed on your first job.&lt;/p&gt;

&lt;p&gt;I promise: it’s not very difficult if you know the basics of Git. But there is a lot of glossary around it that might confuse you at first.&lt;/p&gt;

&lt;p&gt;Watch the video below to see me walk through one cycle of the workflow. Below the video you can find instruction on how to set up branch protection in your GitHub repository to enforce this workflow and a detailed walkthrough based on screenshots.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This series of articles and the application I'm building are part of my &lt;a href="https://profy.dev/waitlist?utm_source=tbd-2&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;upcoming React Job Simulator&lt;/a&gt;. Build a project hands-on like a professional team and gain job-like experience.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Trunk-Based Development in a Nutshell&lt;/li&gt;
&lt;li&gt;Branch Protection: Enforce usage of Pull Requests&lt;/li&gt;
&lt;li&gt;
A tour through the Trunk-Based Development workflow

&lt;ol&gt;
&lt;li&gt;Open a Pull Request&lt;/li&gt;
&lt;li&gt;Continuous Integration Pipeline&lt;/li&gt;
&lt;li&gt;Code Reviews&lt;/li&gt;
&lt;li&gt;Handling Review Comments&lt;/li&gt;
&lt;li&gt;Approving a Pull Request&lt;/li&gt;
&lt;li&gt;Merging the Pull Request&lt;/li&gt;
&lt;li&gt;The history of the main branch&lt;/li&gt;
&lt;li&gt;Updating the local main branch&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Summary&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  Trunk-Based Development in a Nutshell
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You check out a new branch from the main branch.&lt;/li&gt;
&lt;li&gt;You commit your code on this branch and push it to the GitHub repo.&lt;/li&gt;
&lt;li&gt;You open a Pull Request (or Merge Request as GitLab calls it).&lt;/li&gt;
&lt;li&gt;Automated tests verify that the application behaves as expected.&lt;/li&gt;
&lt;li&gt;A teammate reviews your code and you adjust it according to the feedback.&lt;/li&gt;
&lt;li&gt;You merge your branch into the main branch via the Pull Request (short PR).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If this is all sounds like Gibberish, no worries. Have a look at &lt;a href="https://profy.dev/project/github-minesweeper" rel="noopener noreferrer"&gt;my free course where you can learn and practice this workflow&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What the heck is a Pull Request?
&lt;/h2&gt;

&lt;p&gt;I always found the name Pull Request on GitHub confusing. GitLab calls it a Merge Request which is much more descriptive. Basically, a Pull Request is a way to ask for permission to merge your code into the main branch:&lt;/p&gt;

&lt;p&gt;“&lt;em&gt;Hey team, can somebody have a look at this code and tell me if it’s any good? I’d like to get it into the main branch so our users can benefit from it.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can think of a Pull Request as a feature on top of a Git branch that allows you to get feedback from your teammates. And as mentioned it also allows you to automatically run checks and tests on your code changes before they go to the main branch.&lt;/p&gt;

&lt;p&gt;To summarize, Pull Requests are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a mechanism to gather feedback and thus increase code quality&lt;/li&gt;
&lt;li&gt;a tool to run automation (e.g. tests) on your code to decrease the risk of introducing bugs into production code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Branch Protection: Enforce usage of Pull Requests
&lt;/h2&gt;

&lt;p&gt;Processes and workflows are great. But people are lazy and look for workarounds. So ideally we want to force everyone on the team to use Pull Requests instead of committing directly to the main branch.&lt;/p&gt;

&lt;p&gt;Luckily GitHub has our back with a feature called “branch protection”. To protect the main branch open your repository’s settings on GitHub, select “Branches” in the left menu, and click on the “Add rule” button.&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%2Fmedia.graphcms.com%2FJNUZioz4SIGzkLGuywX8" 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%2Fmedia.graphcms.com%2FJNUZioz4SIGzkLGuywX8" alt="GitHub add branch protection rule"&gt;&lt;/a&gt;&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%2Fmedia.graphcms.com%2Fa7wRFUTTO2I6Mkvhkeuf" 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%2Fmedia.graphcms.com%2Fa7wRFUTTO2I6Mkvhkeuf" alt="GitHub branch protection"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few notes about the selected rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In a team of developers the option “Require a Pull Request before merge” → “Require approvals” is mostly activated. This way we can enforce that developers review and approve each other’s code. That is one safeguard against new bugs and ideally increases code quality and coherence.&lt;/li&gt;
&lt;li&gt;The option “Require linear history” is not necessary but from my experience many teams use it nowadays. It prevents merge commits on the respective branch. Instead you have to either “Squash and merge” a Pull Request or “Rebase” it. &lt;a href="https://youtu.be/QH9rhtp_TMk?t=2373" rel="noopener noreferrer"&gt;You can see the “Squash and merge” in action including an explanation here in the video.&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The “Include administrators” option is important if you want to enforce the workflow for yourself in your own repositories. Since you’re the administrator the rules wouldn’t apply to you otherwise.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a developer now creates a commit on the main branch and tries to push it they will see an error message.&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%2Fmedia.graphcms.com%2Fn6XnSXxMQa61x8zwKK0J" 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%2Fmedia.graphcms.com%2Fn6XnSXxMQa61x8zwKK0J" alt="Push to main branch fails"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A tour through the Trunk-Based Development workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Open a Pull Request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;checkout&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="nx"&gt;migrate&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we write our code, commit and push it to the remote repository on GitHub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;commit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Migrate home page to styled-components&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt; &lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="nx"&gt;migrate&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On GitHub, you should now see a banner to create a Pull Request.&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%2Fmedia.graphcms.com%2F0sbFsvGOQFmmAsu5hc87" 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%2Fmedia.graphcms.com%2F0sbFsvGOQFmmAsu5hc87" alt="Create Pull Request banner on GitHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you click the button you see a form where you can enter a title and description. Next click the “Create Pull Request” button.&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%2Fmedia.graphcms.com%2FMquYOS3lQEOlPiAox9iQ" 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%2Fmedia.graphcms.com%2FMquYOS3lQEOlPiAox9iQ" alt="Create Pull Request form on GitHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congrats, you opened your first Pull Request! This is what you should see now:&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%2Fmedia.graphcms.com%2FZNZJn0tQcEGdnA0RfFig" 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%2Fmedia.graphcms.com%2FZNZJn0tQcEGdnA0RfFig" alt="Pull Request on GitHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Continuous Integration Pipeline
&lt;/h3&gt;

&lt;p&gt;Did you note the status checks at the bottom of the PR?&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%2Fmedia.graphcms.com%2FlHT8n4Q3SVGiv6IhrF9Z" 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%2Fmedia.graphcms.com%2FlHT8n4Q3SVGiv6IhrF9Z" alt="Status check for Continuous Integration Pipeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a really handy feature. You can run scripts like &lt;code&gt;npm run lint&lt;/code&gt; or &lt;code&gt;npm run test&lt;/code&gt; within your Pull Requests to decrease the risk of introducing bugs. This is called a Continuous Integration pipeline. I’ll leave it as a cliffhanger for tomorrow’s article. If you can’t wait you can already watch me set it up in the video.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Reviews
&lt;/h3&gt;

&lt;p&gt;In a real-world team, your code is typically reviewed by at least one teammate. This again prevents bugs and helps keep the codebase clean and consistent. A Pull Request is also a great way of discussing your code in case you’re stuck.&lt;/p&gt;

&lt;p&gt;So let’s switch to another account with access to the repository. Here is how our imaginary teammate would review your code.&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%2Fmedia.graphcms.com%2FwxuyaCsLQB63b4koeNPF" 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%2Fmedia.graphcms.com%2FwxuyaCsLQB63b4koeNPF" alt="Pull Request - files changed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our teammate can add comments to the code.&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%2Fmedia.graphcms.com%2FKCkROL6QOeQvvV7kFoUt" 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%2Fmedia.graphcms.com%2FKCkROL6QOeQvvV7kFoUt" alt="Pull Request - review comments"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, they submit the review.&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%2Fmedia.graphcms.com%2Fo3v2TE68TVWTGTxciejV" 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%2Fmedia.graphcms.com%2Fo3v2TE68TVWTGTxciejV" alt="Pull Request - Submit review"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the author of the Pull Request, we can now see the comments.&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%2Fmedia.graphcms.com%2FPXHYoGfSCuf6ivFrcVzw" 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%2Fmedia.graphcms.com%2FPXHYoGfSCuf6ivFrcVzw" alt="Pull Request - Review from author's perspective"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling Review Comments
&lt;/h3&gt;

&lt;p&gt;We have two options now: we can update our code according to the comments or start a discussion.&lt;/p&gt;

&lt;p&gt;To adjust our code we simply head back to our local machine, change the code, commit and push it. You can see the new commit below the review comments. You can also add a comment and resolve the conversation.&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%2Fmedia.graphcms.com%2F61gWRYpCQ820a7cth2Cf" 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%2Fmedia.graphcms.com%2F61gWRYpCQ820a7cth2Cf" alt="Pull Request - Resolve comment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, you can request a new review:&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%2Fmedia.graphcms.com%2FkqWN2AEQE6EbIiFnXOo9" 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%2Fmedia.graphcms.com%2FkqWN2AEQE6EbIiFnXOo9" alt="Pull Request - Request new review"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Approving a Pull Request
&lt;/h3&gt;

&lt;p&gt;Once your teammate is pleased they can approve your Pull Request by submitting a review. They might add a useless yet affirmative emoji comment to make you happy.&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%2Fmedia.graphcms.com%2F6ryF7cPbQKWutMFQpKzF" 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%2Fmedia.graphcms.com%2F6ryF7cPbQKWutMFQpKzF" alt="Pull Request - Approve"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Merging the Pull Request
&lt;/h3&gt;

&lt;p&gt;Finally, it’s time to merge our Pull Request. Now our code changes will be added to the main branch.&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%2Fmedia.graphcms.com%2FVrGSvIPQ0GICNQN1RIKg" 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%2Fmedia.graphcms.com%2FVrGSvIPQ0GICNQN1RIKg" alt="Pull Request - Approved"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember that we set the “Require linear history” option in our branch protection rules? That’s why we see a “Squash and merge” button instead of a simple “Merge” button by default.&lt;/p&gt;

&lt;p&gt;Let’s see what happens when we push the button:&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%2Fmedia.graphcms.com%2F85jO01xT3KdqG1wFoWiV" 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%2Fmedia.graphcms.com%2F85jO01xT3KdqG1wFoWiV" alt="Pull Request - Squash and Merge"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And once we press the confirmation button we’re all set.&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%2Fmedia.graphcms.com%2FDGaaX9YS32Ylv1eqSx5A" 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%2Fmedia.graphcms.com%2FDGaaX9YS32Ylv1eqSx5A" alt="Pull Request - Squashed and merged"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The history of the main branch
&lt;/h3&gt;

&lt;p&gt;I didn’t explain yet what the “Squash and merge” button does, right? The Pull Request (or our Git branch) contained multiple commits:&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%2Fmedia.graphcms.com%2FU4r3wQRASRakvc6Zgx8b" 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%2Fmedia.graphcms.com%2FU4r3wQRASRakvc6Zgx8b" alt="Commits in pull request"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we look at the commit history of our main branch we don’t see these commits anymore. Instead, there’s only a single commit that points to the Pull Request (via the link &lt;code&gt;#6&lt;/code&gt;):&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%2Fmedia.graphcms.com%2FnygmdDZLSUynzgcQP3xY" 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%2Fmedia.graphcms.com%2FnygmdDZLSUynzgcQP3xY" alt="Squashed commit in main branch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the commits of our original branch have been squashed into a single commit. The benefit here is that you don’t need to keep the commits in the Pull Request super tidy. For example, commits that are simple fixes during the review process like “Remove unused class name” don’t really need to show up in the history of the main branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating the local main branch
&lt;/h3&gt;

&lt;p&gt;As the last step (that’s easy to forget) we sync our local main branch with the remote repository. Since the merge happened on GitHub our local machine doesn’t know about these changes in the main branch yet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;pull&lt;/span&gt; &lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we work in a team of developers we should actually do this every time we start working on a new branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this article you learned how to set up a GitHub repository with branch protection to enforce a popular Git workflow called Trunk-Based Development. By now, I hope you're less intimidated by Git &amp;amp; GitHub thanks to the detailed walkthrough.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://profy.dev/waitlist?utm_source=tbd-2&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F907k6850wi7tcskg9bo5.png" alt="React Job Simulator waitlist"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to set up a professional React project (including screencast)</title>
      <dc:creator>Johannes Kettmann</dc:creator>
      <pubDate>Fri, 11 Mar 2022 11:49:10 +0000</pubDate>
      <link>https://forem.com/profydev/how-to-set-up-a-professional-react-project-including-screencast-180f</link>
      <guid>https://forem.com/profydev/how-to-set-up-a-professional-react-project-including-screencast-180f</guid>
      <description>&lt;p&gt;When you start a new React app you might wonder how to set it up in a professional way. What tools should you use? What libraries do you need from the start?&lt;/p&gt;

&lt;p&gt;Based on &lt;a href="https://profy.dev/article/react-tech-stack" rel="noopener noreferrer"&gt;the most popular React tech stack&lt;/a&gt; this article will guide you through the setup of a new application using&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js&lt;/li&gt;
&lt;li&gt;Typescript&lt;/li&gt;
&lt;li&gt;ESLint&lt;/li&gt;
&lt;li&gt;Prettier&lt;/li&gt;
&lt;li&gt;styled-components&lt;/li&gt;
&lt;li&gt;Cypress&lt;/li&gt;
&lt;li&gt;Storybook&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The video below shows how I set up the app for my upcoming &lt;a href="https://profy.dev/waitlist?utm_source=srp-1&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;Bootcamp for Self-Taught React Devs&lt;/a&gt; with exactly this tech stack. The screencast is nearly unedited to show the whole process and not only the polished outcome. If you're looking for a quick guide you can find all steps for the setup on this page.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Next.js &amp;amp; TypeScript
&lt;/h2&gt;

&lt;p&gt;Next.js is the go-to React framework. It has a lot of neat features like server-side-rendering that are important for many professional apps. Many developers tend to use it for any new React project.&lt;/p&gt;

&lt;p&gt;This command creates a new Next.js application using TypeScript. (Feel free to remove the &lt;code&gt;--typescript&lt;/code&gt; option if you already have too much to learn.)&lt;/p&gt;

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

npx create-next-app@latest &lt;span class="nt"&gt;--typescript&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You'll be prompted for a project name and the package manager of your choice. I simply went with npm.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: if you plan to host the project on GitHub you might want to rename the &lt;code&gt;master&lt;/code&gt; branch to &lt;code&gt;main&lt;/code&gt; with this command: &lt;code&gt;git branch -m master main&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ESLint
&lt;/h2&gt;

&lt;p&gt;The Next.js app is already set up with ESLint which is used to detect bugs by statically analyzing your code. &lt;/p&gt;

&lt;p&gt;For my taste, the default rules that come with Next.js are not strict enough though. For example, unused variables don't cause an error. &lt;a href="https://eslint.org/docs/user-guide/getting-started#configuration" rel="noopener noreferrer"&gt;A standard set of rules found in the ESLint docs&lt;/a&gt; is &lt;code&gt;eslint:recommended&lt;/code&gt;. We can extend it in the &lt;code&gt;eslintrc.json&lt;/code&gt; config file.&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&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="s2"&gt;"next/core-web-vitals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"eslint:recommended"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Prettier
&lt;/h2&gt;

&lt;p&gt;Prettier is used to automatically format your code according to a standard. That makes your code more readable and saves you a lot of manual effort. &lt;/p&gt;

&lt;p&gt;You can use a Prettier plugin for your IDE. I use VS Code and &lt;a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode" rel="noopener noreferrer"&gt;its Prettier extension&lt;/a&gt; with the following settings to auto-format when I save a file.&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%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F93b12ee1-af93-4b9b-b6bf-147b414cd0fa%2FUntitled.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%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F93b12ee1-af93-4b9b-b6bf-147b414cd0fa%2FUntitled.png" alt="Untitled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To &lt;a href="https://nextjs.org/docs/basic-features/eslint#prettier" rel="noopener noreferrer"&gt;integrate Prettier with ESLint&lt;/a&gt; you can use the &lt;code&gt;eslint-config-prettier&lt;/code&gt; and add it to your &lt;code&gt;eslintrc.json&lt;/code&gt; config. This way &lt;a href="https://prettier.io/docs/en/integrating-with-linters.html" rel="noopener noreferrer"&gt;you don't get conflicts&lt;/a&gt; between Prettier and ESLint.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; eslint-config-prettier


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

&lt;/div&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&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="s2"&gt;"next/core-web-vitals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"eslint:recommended"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"prettier"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The Next.js app doesn’t use the Prettier format by default. Run &lt;code&gt;npx prettier --write&lt;/code&gt; to format all files.&lt;/p&gt;

&lt;h2&gt;
  
  
  styled-components
&lt;/h2&gt;

&lt;p&gt;styled-components is a very popular library for writing custom CSS. Next.js doesn’t support it out of the box, but this official &lt;a href="https://github.com/vercel/next.js/tree/canary/examples/with-styled-components" rel="noopener noreferrer"&gt;example repo&lt;/a&gt; shows us how to set it up. First, we install the library.&lt;/p&gt;

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

npm &lt;span class="nb"&gt;install &lt;/span&gt;styled-components


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

&lt;/div&gt;

&lt;p&gt;Then we add &lt;code&gt;styledComponents: true&lt;/code&gt; to the compiler option in the &lt;code&gt;next.config.js&lt;/code&gt; file.&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;nextConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;reactStrictMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;compiler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;styledComponents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Additionally, we need to create the &lt;code&gt;pages/_document.tsx&lt;/code&gt; file to avoid a "flash of unstyled content" on the initial page load &lt;a href="https://github.com/vercel/next.js/commit/7ce5d3f2408b08c6121b7edd825615161c616309" rel="noopener noreferrer"&gt;according to the example repo&lt;/a&gt;.&lt;/p&gt;

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

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Document&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/document&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;ServerStyleSheet&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;styled-components&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="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DocumentContext&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/document&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyDocument&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Document&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getInitialProps&lt;/span&gt;&lt;span class="p"&gt;(&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;DocumentContext&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;sheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ServerStyleSheet&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;originalRenderPage&lt;/span&gt; &lt;span class="o"&gt;=&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;renderPage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&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;renderPage&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;originalRenderPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;enhanceApp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&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;props&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;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collectStyles&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;),&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialProps&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;Document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInitialProps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;initialProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;initialProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getStyleElement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&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="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seal&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;That's it. To use global styles or the &lt;code&gt;ThemeProvider&lt;/code&gt; you need to edit the file &lt;code&gt;pages/_app.tsx&lt;/code&gt; as &lt;a href="https://github.com/vercel/next.js/blob/canary/examples/with-styled-components/pages/_app.js" rel="noopener noreferrer"&gt;shown here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cypress
&lt;/h2&gt;

&lt;p&gt;Cypress is a tool that’s commonly used to write end-to-end tests (meaning it tests the whole system from frontend to database just like a real user).&lt;/p&gt;

&lt;p&gt;For the setup, &lt;a href="https://nextjs.org/docs/testing#manual-setup" rel="noopener noreferrer"&gt;the Next.js docs&lt;/a&gt; are again very helpful. First, we install Cypress.&lt;/p&gt;

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

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; cypress


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

&lt;/div&gt;

&lt;p&gt;Then we add &lt;code&gt;"cypress": "cypress open"&lt;/code&gt; to the &lt;code&gt;scripts&lt;/code&gt; section in our &lt;code&gt;package.json&lt;/code&gt; file.&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&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;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next dev"&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;"next 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;"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;"next 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;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next lint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cypress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cypress open"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally, run &lt;code&gt;npm run cypress&lt;/code&gt; to initialize the project. This creates a few folders and demo tests in your repository. Then the Cypress UI opens where you can run the demo tests.&lt;/p&gt;

&lt;p&gt;When you open the test files you'll realize that ESLint complains that global functions like &lt;code&gt;describe&lt;/code&gt; or &lt;code&gt;it&lt;/code&gt; don't exist. To get rid of these errors we can install an ESLint plugin and adjust the &lt;code&gt;eslintsrc.json&lt;/code&gt; config file.&lt;/p&gt;

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

npm &lt;span class="nb"&gt;install &lt;/span&gt;eslint-plugin-cypress &lt;span class="nt"&gt;--save-dev&lt;/span&gt;


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

&lt;/div&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&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="s2"&gt;"next/core-web-vitals"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"eslint:recommended"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"prettier"&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;"plugins"&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="s2"&gt;"cypress"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"cypress/globals"&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="w"&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Storybook
&lt;/h2&gt;

&lt;p&gt;Storybook is a tool widely used to document and visually test UI components. &lt;a href="https://storybook.js.org/docs/react/get-started/install" rel="noopener noreferrer"&gt;According to the docs&lt;/a&gt; we first need to initialize or project.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx sb init


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

&lt;/div&gt;

&lt;p&gt;Then run Storybook. This will open a new browser tab where you can play around with some demo components.&lt;/p&gt;

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

npm run storybook


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://profy.dev/waitlist?utm_source=srp-2&amp;amp;utm_medium=devto" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0a7pa5bdyj2tip5om7p.png" alt="Bootcamp for Self-Taught React devs"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
