<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Snigdho Dip Howlader</title>
    <description>The latest articles on DEV Community by Snigdho Dip Howlader (@snigdho611).</description>
    <link>https://dev.to/snigdho611</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F923850%2F86277586-dd03-4ce4-b218-b01ca4c29f79.jpg</url>
      <title>DEV Community: Snigdho Dip Howlader</title>
      <link>https://dev.to/snigdho611</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/snigdho611"/>
    <language>en</language>
    <item>
      <title>Docker Compose for a Full-Stack Application with React, Node.js, and PostgreSQL</title>
      <dc:creator>Snigdho Dip Howlader</dc:creator>
      <pubDate>Fri, 14 Jun 2024 18:11:17 +0000</pubDate>
      <link>https://dev.to/snigdho611/docker-compose-for-a-full-stack-application-with-react-nodejs-and-postgresql-3kdl</link>
      <guid>https://dev.to/snigdho611/docker-compose-for-a-full-stack-application-with-react-nodejs-and-postgresql-3kdl</guid>
      <description>&lt;h3&gt;
  
  
  The Premise
&lt;/h3&gt;

&lt;p&gt;So you've built a Full Stack application that you got working as you wanted, and want to show it off. However, dependencies and environments make it so that it only runs on your device. Well, as you already may know that Docker Compose can take care of that. Let's start going through how this can be done without further ado. This tutorial is for those who have some idea on creating applications and servers, and some basic knowledge of Docker as well.&lt;/p&gt;

&lt;h4&gt;
  
  
  TL;DR
&lt;/h4&gt;

&lt;p&gt;The source code can be found &lt;a href="https://github.com/snigdho611/docker-compose-react-nodejs-postgres" rel="noopener noreferrer"&gt;here on Github&lt;/a&gt;. To get this project up and running, follow these steps&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make sure you have Docker installed in your system. For installation steps, follow the following steps:

&lt;ol&gt;
&lt;li&gt;For &lt;strong&gt;&lt;a href="https://docs.docker.com/desktop/install/mac-install/" rel="noopener noreferrer"&gt;Mac&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;&lt;a href="https://docs.docker.com/engine/install/ubuntu/" rel="noopener noreferrer"&gt;Ubuntu&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;For &lt;strong&gt;&lt;a href="https://docs.docker.com/desktop/install/linux-install/" rel="noopener noreferrer"&gt;Windows&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Clone the repository into your device&lt;/li&gt;

&lt;li&gt;Open a terminal from the cloned project's directory (Where the &lt;code&gt;docker-compose.yml&lt;/code&gt; file is present)&lt;/li&gt;

&lt;li&gt;Run the command: &lt;code&gt;docker compose up&lt;/code&gt;
&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;That's all! That should get the project up and running. To see the output, you can access &lt;code&gt;http://127.0.0.1:4172&lt;/code&gt; from the browser and you should find a web page with a list of users. This entire system with the client, server &amp;amp; database are running inside of docker and being accessible from your machine.&lt;/p&gt;

&lt;p&gt;Here is a detailed explanation on what is going on.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Introduction&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; at its core is a platform as a service that uses OS-level virtualization to deploy/deliver software in packages called containers. It is done for various advantages, such as cross platform consistency and flexibility and scalability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt; is a tool for defining and running multi-container applications. It is the key to unlocking a streamlined and efficient development and deployment experience.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Using Docker and Docker Compose&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When it comes to working with Full Stack Applications, i.e. ones that will involve more than one set of technology to integrate it into one fully fledged system, Docker can be fairly overwhelming to configure from scratch. It is not made any easier by the fact that there are various types of environment dependencies for each particular technology, and it only leads to the risk of errors at a deployment level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;code&gt;.env&lt;/code&gt; file adjacent in the directory with &lt;code&gt;docker-compose.yml&lt;/code&gt; will contain certain variables that will be used in the docker compose file. They will be accessed whenever the &lt;code&gt;${&amp;lt;VARIABLE_NAME&amp;gt;}&lt;/code&gt; notation is used.&lt;/p&gt;

&lt;p&gt;This example will work with PostgreSQL as the database, a very minimal Node/Express JS server and React JS as the client side application.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Individual Containers&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The following section goes into a breakdown of how the &lt;code&gt;docker-compose.yml&lt;/code&gt; file works with the individual &lt;code&gt;Dockerfile&lt;/code&gt;. Let's take a look at the docker-compose file first. We have a key called &lt;code&gt;services&lt;/code&gt; at the very top, which defines the different applications/services we want to get running. As this is a &lt;code&gt;.yml&lt;/code&gt; file, it is important to remember that indentations are crucial. Lets dive into the first service defined in this docker compose file, the database.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;1. Database&lt;/strong&gt;
&lt;/h5&gt;

&lt;p&gt;First of all, the database needs to be set up and running in order for the server to be able to connect to it. The database does not need any Dockerfile in this particular instance, however, it can be done with a Dockerfile too. Lets go through the configurations.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/em&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="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database&lt;/span&gt;
    &lt;span class="na"&gt;ports&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;5431:5432"&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
        &lt;span class="s"&gt;environment&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${POSTGRES_USER}"&lt;/span&gt;
            &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${POSTGRES_PASSWORD}"&lt;/span&gt;
            &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${POSTGRES_DB}&lt;/span&gt;
        &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./docker_test_db:/var/lib/postgresql/data&lt;/span&gt;
        &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;test&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;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sh&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-c&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;${POSTGRES_USER}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;${POSTGRES_DB}'"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
            &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
            &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60s&lt;/span&gt;
            &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
            &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;80s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Explanation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;postgres&lt;/em&gt;&lt;/strong&gt;: used to identify the service that the section of the compose file is for&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;container_name&lt;/em&gt;&lt;/strong&gt;: the name of the service/container that we have chosen&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;ports&lt;/em&gt;&lt;/strong&gt;: maps the host port (making it accessible from outside) to the port being used by the application in Docker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;image&lt;/em&gt;&lt;/strong&gt;: defines the Docker image that will be required to make this container functional and running&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;environment&lt;/em&gt;&lt;/strong&gt;: defined variables for the environment of this particular service. For example, for this PostgreSQL service, we will be defining a &lt;code&gt;POSTGRES_USER&lt;/code&gt;,&lt;code&gt;POSTGRES_PASSWORD&lt;/code&gt; and &lt;code&gt;POSTGRES_DB&lt;/code&gt;. They're all being assigned with the values in the &lt;code&gt;.env&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;volumes&lt;/em&gt;&lt;/strong&gt;: This particular key is for we want to create a container that can &lt;strong&gt;&lt;em&gt;persist&lt;/em&gt;&lt;/strong&gt; data. This means that ordinarily, when a Docker container goes down, so does any updated data on it. Using volumes, we are mapping a particular directory of our local machine with a directory of the container. In this case, that's the directory where postgres is reading the data from for this database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;heathcheck&lt;/em&gt;&lt;/strong&gt;: when required, certain services will need to check if their state is functional or not. For example, PostgreSQL, has a behavior of turning itself on and off a few instances at launch, before finally being functional. For this reason, healthcheck allows Docker Compose to allow other services to know when it is fully functional.
The few properties below healthcheck are doing the following:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;test&lt;/em&gt;&lt;/strong&gt;: runs particular commands for the service to run checks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;interval&lt;/em&gt;&lt;/strong&gt;: amount of time docker compose will wait before running a check again&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;timeout&lt;/em&gt;&lt;/strong&gt;: amount of time that the a single check will go on for, before it times out without any response or fails&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;retries&lt;/em&gt;&lt;/strong&gt;: total number of tries that docker compose will try to get the healthcheck for a positive response, otherwise fail and declare it as a failed check&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;start_period&lt;/em&gt;&lt;/strong&gt;: specifies the amount of time to wait before starting health checks&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;2. Server&lt;/strong&gt;
&lt;/h5&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /server&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src/ /server/src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; prisma/ /server/prisma&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json /server&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npx prisma generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;FROM&lt;/em&gt;&lt;/strong&gt; - tells Docker what image is going to be required to build the container. For this example, its the Node JS (version 18)&lt;br&gt;
&lt;strong&gt;&lt;em&gt;WORKDIR&lt;/em&gt;&lt;/strong&gt; - sets the current working directory for subsequent instructions in the Dockerfile. The &lt;code&gt;server&lt;/code&gt; directory will be created for this container in Docker's environment&lt;br&gt;
&lt;strong&gt;&lt;em&gt;COPY&lt;/em&gt;&lt;/strong&gt; - separated by a space, this command tells Docker to copy files/folders &lt;strong&gt;&lt;em&gt;from local environment to the Docker environment&lt;/em&gt;&lt;/strong&gt;. The code above is saying that all the contents in the src and prisma folders need to be copied to the &lt;code&gt;/server/src&lt;/code&gt; &amp;amp; &lt;code&gt;/srver/prisma&lt;/code&gt; folders in Docker, and package.json to be copied to the &lt;code&gt;server&lt;/code&gt; directory's root.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;RUN&lt;/em&gt;&lt;/strong&gt; - executes commands in the terminal. The commands in the code above will install the necessary node modules, and also generate a prisma client for interacting with the database (it will be needed for seeding the database initially).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/em&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="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./server&lt;/span&gt;
        &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;ports&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;7999:8000"&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash -c "npx prisma migrate reset --force &amp;amp;&amp;amp; npm start"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${DATABASE_URL}"&lt;/span&gt;
        &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${SERVER_PORT}"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;build&lt;/em&gt;&lt;/strong&gt;: defines the build context for the container. This can contain steps to build the container, or contain path to Dockerfiles that have the instructions written. The &lt;strong&gt;&lt;em&gt;context&lt;/em&gt;&lt;/strong&gt; key directs the path, and the &lt;strong&gt;&lt;em&gt;dockerfile&lt;/em&gt;&lt;/strong&gt; key contains the name of the Dockerfile.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;command&lt;/em&gt;&lt;/strong&gt;: executes commands according to the instructions that are given. This particular command is executed to first make migrations to the database and seed it, and then start the server.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;environment&lt;/em&gt;&lt;/strong&gt;: contains the key-value pairs for the environment, which are available in the .env file at the root directory. &lt;code&gt;DATABASE_URL&lt;/code&gt; and &lt;code&gt;PORT&lt;/code&gt; both contain corresponding values in the .env file.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;depends_on&lt;/em&gt;&lt;/strong&gt;: checks if the dependent container is up, running and functional or not. This has various properties, but in this example, it is checking if the &lt;code&gt;service_healthy&lt;/code&gt; flag of our postgres container is up and functional or not. The &lt;code&gt;server&lt;/code&gt; container will only start if this flag is returned being &lt;code&gt;true&lt;/code&gt; from the &lt;strong&gt;&lt;em&gt;healthcheck&lt;/em&gt;&lt;/strong&gt; from the PostgreSQL &lt;/p&gt;
&lt;h5&gt;
  
  
  &lt;strong&gt;3. Client&lt;/strong&gt;
&lt;/h5&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; VITE_SERVER_URL=http://127.0.0.1:7999&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; VITE_SERVER_URL=$VITE_SERVER_URL&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /client&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; public/ /client/public&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src/ /client/src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; index.html /client/&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json /client/&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; vite.config.js /client/&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;&lt;br&gt;
Note: &lt;em&gt;The commands for &lt;code&gt;client&lt;/code&gt; are very similar to the already explained above for &lt;code&gt;server&lt;/code&gt;&lt;/em&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;ARG&lt;/em&gt;&lt;/strong&gt;: defines a variable that is later passed to the &lt;strong&gt;&lt;em&gt;ENV&lt;/em&gt;&lt;/strong&gt; instruction&lt;br&gt;
&lt;strong&gt;&lt;em&gt;ENV&lt;/em&gt;&lt;/strong&gt;: Assigns a key value pair into the context of the Docker environment for the container to run. This essentially contains the domain of the API that will be fired from the client later.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/em&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="na"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;client&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./client&lt;/span&gt;
        &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash -c "npm run preview"&lt;/span&gt;
    &lt;span class="na"&gt;ports&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;4172:4173"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation&lt;/strong&gt;&lt;br&gt;
Note: &lt;em&gt;The commands for &lt;code&gt;client&lt;/code&gt; are very similar to the already explained above for &lt;code&gt;server&lt;/code&gt; and &lt;code&gt;postgres&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This tutorial provides a basic understanding of using Docker Compose to manage a full-stack application. Explore the code and docker-compose.yml file for further details. The source code can be found &lt;a href="https://github.com/snigdho611/docker-compose-react-nodejs-postgres" rel="noopener noreferrer"&gt;here on Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>node</category>
      <category>postgres</category>
      <category>react</category>
    </item>
    <item>
      <title>Setting up Redux Persist with Redux Toolkit in React JS</title>
      <dc:creator>Snigdho Dip Howlader</dc:creator>
      <pubDate>Fri, 03 Nov 2023 23:27:10 +0000</pubDate>
      <link>https://dev.to/snigdho611/setting-up-redux-persist-with-redux-toolkit-in-react-js-30kn</link>
      <guid>https://dev.to/snigdho611/setting-up-redux-persist-with-redux-toolkit-in-react-js-30kn</guid>
      <description>&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%2Fcyg12qxcz8jaksiz65pp.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%2Fcyg12qxcz8jaksiz65pp.png" alt="Redux banner image" width="800" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;State management is a fundamental aspect of building modern web applications. As an application grows, managing and maintaining the states can become rather daunting. &lt;a href="https://redux.js.org/" rel="noopener noreferrer"&gt;Redux&lt;/a&gt;, a popular JavaScript library, has been the go-to solution for state management in React applications for a while now. &lt;/p&gt;

&lt;p&gt;However, Redux, or pure Redux to be specific, can be quite verbose and boilerplate-heavy. It requires a significantly lengthy setup, which is where &lt;a href="https://redux-toolkit.js.org/" rel="noopener noreferrer"&gt;Redux Toolkit&lt;/a&gt; comes in handy, offering a simplified and more efficient way to set up and manage state in your React applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Redux Toolkit?
&lt;/h3&gt;

&lt;p&gt;Redux Toolkit is a much simpler way to set up and use Redux without the need to create large amounts of boilerplate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Redux Persist
&lt;/h3&gt;

&lt;p&gt;Redux helps applications hold onto data when navigating from page to page, which is known as the global state. However, as most people who are familiar with Redux will know, the global state will be reset the moment the application is reset.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Redux Toolkit with Redux Persist
&lt;/h3&gt;

&lt;p&gt;The following tutorial will implement a simple login system, to fetch data to store it in Redux and into the localStorage (default) with Redux Persist. This way, routes can be restricted depending on the existence of data being present in the browser storage. &lt;/p&gt;

&lt;p&gt;Custom hooks can do all of this, but the behavior may not always be consistent on all browsers, and the implementation can lead to UI inconsistencies. Redux Persist ensures that the app does not get loaded before the available data is fetched from the browser memory, and then lets the logic flow as it is implemented.&lt;/p&gt;

&lt;p&gt;To follow along and understand this tutorial properly, here are some topics that you should have some idea about beforehand:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;React JS&lt;/li&gt;
&lt;li&gt;Redux&lt;/li&gt;
&lt;li&gt;Redux Toolkit&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Setting up the React JS Project
&lt;/h3&gt;

&lt;p&gt;First of all, the React project must be set up, and I'll use Vite to do this as it is easy to use. Run the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; npm create vite@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be given a couple of prompts, such as the name of the project, which can be whatever you want. I named mine 'auth-redux'. Next, the prompt will be given to select the framework, I went with React and then when prompted for a variant, I selected JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;✔ Project name: auth-redux
✔ Select a framework: React
✔ Select a variant: JavaScript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the setup is created, run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install the necessary &lt;code&gt;node_modules&lt;/code&gt; to get you started. Finally, to see the server go live, run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Installing Redux, Redux Toolkit and Redux Persist
&lt;/h3&gt;

&lt;p&gt;With your server set up, it's time to install react-redux, redux-toolkit, and redux-persist, along with react-router-dom, which will be needed for navigating pages in React. We will also install Sass, to use &lt;code&gt;.scss&lt;/code&gt; files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; npm i react-router-dom react-redux @reduxjs/toolkit redux-persist sass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the setup is complete, we can proceed to create the project itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Login Module
&lt;/h3&gt;

&lt;p&gt;For those who want to check every file and module used in the project, the code is available &lt;a href="https://github.com/snigdho611/auth-redux" rel="noopener noreferrer"&gt;here&lt;/a&gt; for you to follow along with. There is also a TypeScript version in a separate branch for those who require it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--src/
  --assets/
  --components/
    --common/
      --Navbar
        --index.jsx
        --index.scss
    --pages/
      --Home
        --index.jsx
        --index.scss
      --Login
        --index.jsx
        --index.scss
  --App.css
  --App.jsx
  --main.jsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The project&lt;/strong&gt; - two pages, a home page, and a login page. &lt;br&gt;
&lt;strong&gt;The goal&lt;/strong&gt; - to ensure that after logging in, the user is redirected to the home page. If the home page is attempted to be loaded manually in the browser by hitting the URL without logging in, it will redirect back to login. We will try to check and keep track of the login status using Redux and localStorage.&lt;/p&gt;

&lt;p&gt;Creating a login form and a home page is fairly simple if you know React JS and CSS/SCSS. Here are the two pages I have implemented. &lt;/p&gt;

&lt;p&gt;Log in:&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%2F91zayi8z7w2am4byek1a.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%2F91zayi8z7w2am4byek1a.png" alt="Log in Page" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Home:&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%2Fi6hv8fvas9mlvxyfnd6d.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%2Fi6hv8fvas9mlvxyfnd6d.png" alt="Home Page" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The Redux and Redux Persist Setup
&lt;/h3&gt;

&lt;p&gt;Once the pages and necessary components are set up, we can move to explaining the Redux logic. I will be implementing everything related to Redux inside a folder called &lt;code&gt;store&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, we'll create a "slice" for the initial state of Redux. You can read more on creating Redux Slices &lt;a href="https://redux-toolkit.js.org/api/createslice" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Essentially, it will be an object, that will contain some properties as null.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then use this to create our slice. We will create a couple of reducer functions to implement our logic for saving data when a user logs in, and removing data when a user logs out. This can be done with the syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSlice&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;@reduxjs/toolkit&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;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authSlice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSlice&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;auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;reducers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;saveLogin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gender&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;removeLogin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="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;export&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;saveLogin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;removeLogin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;authSlice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;authSlice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the slice created, we can now move on to create the store itself and the logic to persist the data. Now, we will create the universal reducer using &lt;code&gt;combineReducers&lt;/code&gt; function from redux toolkit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;combineReducers&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;@reduxjs/toolkit&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;authSlice&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;./auth&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;reducers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;combineReducers&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;authSlice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we have to set up the Redux Persist mechanism that will be able to retain the data using localStorage. We can do this by creating an object for the persist configuration, and it will require a key and a storage value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;persistConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;whitelist&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;auth&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;Almost done, now using the reducers and persistConfig:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;persistedReducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;persistReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;persistConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reducers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating the store and the persistor objects to export them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;configureStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;persistedReducer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getDefaultMiddleware&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;getDefaultMiddleware&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;serializableCheck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;ignoredActions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;PERSIST&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;persistor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;persistStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;persistor&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The persistor object is what will now be able to ensure that the initialState is created as soon as the app is loaded in the browser, and afterward, Redux Toolkit can handle the further functionalities.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;main.tsx&lt;/code&gt;, which is the parent of &lt;code&gt;App.jsx&lt;/code&gt;, we will write the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.jsx&lt;/span&gt;&lt;span class="dl"&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;persistor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./store/index.js&lt;/span&gt;&lt;span class="dl"&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;Provider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-redux&lt;/span&gt;&lt;span class="dl"&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;PersistGate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redux-persist/integration/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PersistGate&lt;/span&gt; &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;persistor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;persistor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;PersistGate&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are wrapping the App component in the &lt;code&gt;PersistGate&lt;/code&gt; to ensure that the App does not load until the data fetch/reception is completed between the application and the browser storage by passing the persistor object it that we created earlier. I have set the loading value to null, but you can use this to implement loading screens/components before data is properly loaded into Redux from storage. &lt;/p&gt;

&lt;p&gt;And over that, we are wrapping the &lt;code&gt;PersistGate&lt;/code&gt; component in the &lt;code&gt;Provider&lt;/code&gt; component from Redux, passing the store as a prop so Redux Toolkit can handle the basic functionalities.&lt;/p&gt;

&lt;h3&gt;
  
  
  How the Private Route Logic Works
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;App.jsx&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App.css&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;BrowserRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Navigate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-router-dom&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;Login&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;./components/pages/Login&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;Home&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;./components/pages/Home&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;PrivateRoute&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;./components/common/PrivateRoute&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;useSelector&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-redux&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BrowserRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Navigate&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/login"&lt;/span&gt; &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&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;&lt;/span&gt;&lt;span class="nc"&gt;Login&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Navigate&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/page&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PrivateRoute&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/page"&lt;/span&gt; &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Home&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;BrowserRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;PrivateRoute&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Navigate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Outlet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-router-dom&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;useSelector&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-redux&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;PrivateRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSelector&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&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;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&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;Outlet&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;Navigate&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;"&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;PrivateRoute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the PrivateRoute component is going to check if the username, id, and token exist or not. Even if the app is reloaded, the &lt;code&gt;PersistGate&lt;/code&gt; along with the &lt;code&gt;persistor&lt;/code&gt; object will make sure that the data is fetched from the localStorage in the browser. It will then allow navigation to the &lt;code&gt;&amp;lt;Outlet /&amp;gt;&lt;/code&gt; (Whatever component is supposed to be accessible), otherwise it will navigate back to the login page. &lt;/p&gt;

&lt;h3&gt;
  
  
  Redux Toolkit and Redux Persist at Work
&lt;/h3&gt;

&lt;p&gt;Using the Inspect tab to monitor the data in the local storage, on first load, you can find that the data of the initial state is saved here in the login page as all properties set to null in the auth object.&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%2F02lzvft57bclfivqhfbw.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%2F02lzvft57bclfivqhfbw.png" alt="Before logging in" width="800" height="818"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After logging in, the data is updated accordingly to the response that is being sent from the login API. Every time you try to navigate to the login page now, you will be redirected back to login.&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%2Fyvsyb2lh7ftwpiarfrzy.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%2Fyvsyb2lh7ftwpiarfrzy.png" alt="After logging in" width="800" height="818"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Redux can be fairly complex to work with, but Redux Toolkit makes it a lot easier when setting it up and creating the reducers. Redux Persist lets saving and fetching data into browser storage much more easily and conveniently and allows React applications to depend on browser storage when creating private routes to stop users from accessing certain features - even after hard reloading the application.&lt;/p&gt;

&lt;p&gt;All of the source code for this project are available &lt;a href="https://github.com/snigdho611/auth-redux" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>redux</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>SQL Injections at Work</title>
      <dc:creator>Snigdho Dip Howlader</dc:creator>
      <pubDate>Wed, 25 Oct 2023 17:35:52 +0000</pubDate>
      <link>https://dev.to/snigdho611/sql-injections-at-work-ijm</link>
      <guid>https://dev.to/snigdho611/sql-injections-at-work-ijm</guid>
      <description>&lt;h3&gt;SQL Injection&lt;/h3&gt;

&lt;p&gt;SQL Injection, or SQLI is a means to attack a website or server, with the intention of manipulating the back-end and database to run &lt;em&gt;malicious&lt;/em&gt; queries as per desire of the attacker.&lt;/p&gt;

&lt;p&gt;Although SQL Injection is an aged form of cyber attack, and most systems likely have taken measures against this - it often does not end up being the case. It can be caused by lack of priority or planning, but plenty of systems even today implement security measures but overlook the possibilities of SQL injections. As a developer, it is natural to have come across the term SQLI or SQL Injection fairly frequently. However, most of the time, the preventive measures are taken against this type of attack without actually understanding what the attacker is doing or trying to do. &lt;/p&gt;

&lt;p&gt;In this article, I will provide a very simple example of a log in system that is vulnerable to SQL Injection, and how the SQL Injection can actually be done to allow the attacker into the system without having the correct user password.&lt;/p&gt;

&lt;h3&gt;A Simple Example&lt;/h3&gt;

&lt;p&gt;To understand the tutorial effectively, some basic understanding of the following topics is expected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL&lt;/li&gt;
&lt;li&gt;JavaScript (Basic Client Side Web Programming)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's take a look at the query we will be using throughout the tutorial: &lt;br&gt;
&lt;code&gt;SELECT * FROM users WHERE email = &amp;lt;email&amp;gt; $email AND password = &amp;lt;password&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This query will be executed in the example using PHP to check for a user with the email and user provided from the client. &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%2Fkmaplz30itv6oofdlk05.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%2Fkmaplz30itv6oofdlk05.png" alt="Simple log in form" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a simple log in form, and for demonstration purposes, the query that is expected to be executed is shown above it. This will help visualize exactly what is going 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk04bgmfu82o4soedbh7p.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%2Fk04bgmfu82o4soedbh7p.png" alt="Failed log in attempt" width="800" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the first attempt, the wrong credentials are entered, and the message is shown accordingly below the form. In a scenario where you do not know the password, this is where things would stop on your end. However, with SQL Injection, things can be made out to be more interesting.&lt;/p&gt;

&lt;h3&gt;The Injection Step&lt;/h3&gt;

&lt;p&gt;Remember that with most SQL queries, there will be single quotes that wrap the data that is being queried against, such as '&lt;a href="mailto:john.doe@gmail.com"&gt;john.doe@gmail.com&lt;/a&gt;' and 'Admin@123' in this example. A system vulnerable to SQL injections will be unable to handle a scenario where SQL syntaxes are entered into the inputs themselves. &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%2Fe7zvpd3n6brzufw9fyjo.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%2Fe7zvpd3n6brzufw9fyjo.png" alt="Launching the attack" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On first read, it may seem like much has not changed. However, if a closer look is taken at the network tab of the browser, it can be seen that the error message has changed drastically. The single quote after the email field has tossed the server into disarray, because it was not expecting the single quote (or any SQL syntax for that matter). Note exactly how the query in the browser above the form has also changed, and it ultimately has broken the query.&lt;/p&gt;

&lt;p&gt;This tells us that we can manipulate the input field in a way that lets us &lt;em&gt;inject&lt;/em&gt; SQL directly into code of the server. Now we can proceed to how this can get malicious.&lt;/p&gt;

&lt;p&gt;If we try using SQL logic to beat the system, the process becomes a cakewalk. Suppose you want to add a logic to add to the existing query that is always going to be true no matter what - such as '0'=='0', because zero will always be equal to zero! By default, SQL will look at AND statements before looking at the OR. Using this to our advantage, we can add &lt;em&gt;' OR '0'=='0'&lt;/em&gt; in the email field. &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%2F54o1ystlbdfuzhlhuk3v.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%2F54o1ystlbdfuzhlhuk3v.png" alt="Injecting SQL maliciously" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not surprisingly enough, the authentication has been bypassed and the user has been logged into the system without ever providing a correct password. So what did actually happen? Well, if we were to take a look at the query we created by injecting the SQL into the email field, this is what we get from the screenshot above: &lt;code&gt;SELECT * FROM users WHERE email = 'john.doe@gmail.com' OR '0'='0' AND password = 'Admin@123'&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;This means that the AND operator will try to execute, and fail at first, but then when the OR operator executes, it essentially only checks if the email is matching OR if the statement '0' = '0' is occurring or not, which as mentioned earlier, will always be true. This way, this SQL statement will end up being true in every single scenario regardless of whether the password matches or not, as the OR statement will execute with a condition that will always be true, and ultimately result in a truthy result no matter what. &lt;/p&gt;

&lt;h3&gt;Another approach&lt;/h3&gt;

&lt;p&gt;Here's another way for this example:&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%2F6u76gh7uxd4w6qocmpjw.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%2F6u76gh7uxd4w6qocmpjw.png" alt="Injecting SQL maliciously differently" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once again, this time in much simpler fashion, the authentication has been bypassed. Remember that &lt;em&gt;--&lt;/em&gt; is actually considered as a comment in most SQL systems, and therefore in this example, the final query is just the email field being checked, and the password field being completely ignored.&lt;/p&gt;

&lt;p&gt;This was a simple example of how In-band Error-based SQL Injection can work, and there are other types such as Inferential (Blind) SQLi and Out-of-band SQLi. Although most of the cyber world always takes measures against these kinds of attacks, its always important to remember that what may be seen as a low priority in a security measure is always most likely going to be used by hackers and attackers. &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html" rel="noopener noreferrer"&gt;Prepared Statements&lt;/a&gt; on the server-end are among the easiest and simplest ways to avoid vulnerability to SQL injections. &lt;/p&gt;

&lt;p&gt;Please remember that the purpose of this tutorial is strictly educational, and not at all to promote any sort of illegal activities. It is important for a developer to know how attacks actually happen, in order to take measurements against them. &lt;/p&gt;

&lt;p&gt;This example is done with HTML, CSS, JavaScript and PHP on the server-side. &lt;br&gt;
Github source code: &lt;a href="https://github.com/snigdho611/sql-injection" rel="noopener noreferrer"&gt;https://github.com/snigdho611/sql-injection&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>php</category>
      <category>javascript</category>
      <category>security</category>
    </item>
    <item>
      <title>React JS: Interceptors with Fetch API</title>
      <dc:creator>Snigdho Dip Howlader</dc:creator>
      <pubDate>Thu, 15 Sep 2022 15:57:43 +0000</pubDate>
      <link>https://dev.to/snigdho611/react-js-interceptors-with-fetch-api-1oei</link>
      <guid>https://dev.to/snigdho611/react-js-interceptors-with-fetch-api-1oei</guid>
      <description>&lt;h2&gt;
  
  
  What are Interceptors?
&lt;/h2&gt;

&lt;p&gt;Interceptors are a way to trigger specific functionalities before or after a request is made, or a response is received respectively. One of the most commonly used reasons for interception is authentication on the frontend, or re-routing an API URL to something other than the original. &lt;/p&gt;

&lt;h2&gt;
  
  
  Fetch API
&lt;/h2&gt;

&lt;p&gt;The Fetch API is a very simple and effective way to handle requests and responses with JavaScript or any JavaScript frontend libraries. Namely, React JS has used it quite a lot before the rise of the extremely popular Axios library. Axios actually has some in-built ways to handle interception, both for requests and responses.&lt;/p&gt;

&lt;p&gt;However, when working with or maintaining code that is a bit older, Axios may not have been as widely used then as it is used today - and the &lt;strong&gt;Fetch API&lt;/strong&gt; was the only way to advance. &lt;/p&gt;

&lt;h2&gt;
  
  
  Intercepting with the Fetch API
&lt;/h2&gt;

&lt;p&gt;To put it simply, Fetch API interception is quite easy to do because all that's needed to be done is re-write the fetch function itself. The fetch function takes in two parameters, the resource (the URL) and the config, after which the Promise can be handled. &lt;/p&gt;

&lt;p&gt;The following is an easy way to understand the fetch API function. Destructuring the &lt;strong&gt;_originalFetch _&lt;/strong&gt; function from the window.fetch, you can use it to then get the &lt;strong&gt;&lt;em&gt;resource&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;config&lt;/em&gt;&lt;/strong&gt; mentioned earlier from the arguments of window.fetch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;originalFetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;originalFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&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;response&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;Any functionality you write here will be executed each time a fetch call is made once this code chunk has been loaded into React JS. For testing, you can simply put this inside a useEffect in App.js, and log something into the console inside this function. Every time onwards a fetch call is made, that particular console log will be executed.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to intercept requests with React JS
&lt;/h2&gt;

&lt;p&gt;For this demonstration, we are attempting to re-route a fetch call to a dummy JSON generator for posts, to one for quotes instead. Every call made to get posts will instead be re-directed to get quotes and shown in the frontend instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;originalFetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;URLcutOff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://dummyjson.com&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;trailing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;URLcutOff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;trailing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/posts&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;resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://dummyjson.com/quotes?limit=5`&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;originalFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;config&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;response&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 is the code that will be doing it. Essentially, it is going to remove the base part of the resource URL and check if it has a trailing section that contains the characters "/posts", it will instead be replaced by "/quotes". Since the resource is being changed mid-way, the originalFetch function will now use the changed resource and return the response that is sent back from it. &lt;/p&gt;

&lt;p&gt;It is that simple! You can re-write this code to try out your own API calls instead of the two that are provided here. A React project is set up for you to try this out on your own from. It has a frontend with a pair of buttons. One button (Posts) to return the data for posts, and another button (Intercept) that will stop making calls to the posts resource every time you click the Posts button, and instead make calls to the quotes resource. &lt;/p&gt;

&lt;h2&gt;
  
  
  Demonstration:
&lt;/h2&gt;

&lt;p&gt;When the &lt;code&gt;Posts&lt;/code&gt; button is clicked:&lt;br&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%2F6fmktxzj5ollcvn3zc7h.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%2F6fmktxzj5ollcvn3zc7h.png" alt="Event effect after clicking Posts" width="800" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the &lt;code&gt;Posts&lt;/code&gt; button is clicked after clicking the &lt;code&gt;Intercept&lt;/code&gt; button:&lt;br&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%2Fhfb2ambqyfd534b4p4z9.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%2Fhfb2ambqyfd534b4p4z9.png" alt="Event effect after clicking Intercept" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can even see in the inspect tab, that the quotes API is called even after the Posts button is being clicked.&lt;/p&gt;

&lt;p&gt;That was it for a simple demonstration of monkey patching with request interception using the Fetch API. Here's &lt;a href="https://github.com/snigdho611/fetch-interceptor" rel="noopener noreferrer"&gt;a link&lt;/a&gt; to the repository that contains all the source code in React JS.&lt;/p&gt;

&lt;p&gt;Source Code: &lt;a href="https://github.com/snigdho611/fetch-interceptor" rel="noopener noreferrer"&gt;https://github.com/snigdho611/fetch-interceptor&lt;/a&gt;&lt;br&gt;
By: &lt;a href="https://github.com/snigdho611" rel="noopener noreferrer"&gt;Snigdho Dip Howlader&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>api</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
