<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Yogesh Chavan]]></title><description><![CDATA[Full Stack Developer | JavaScript | React | Nodejs.  Subscribe to my YouTube Channel: https://www.youtube.com/@codingmastery_dev]]></description><link>https://blog.yogeshchavan.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 12 Apr 2026 23:05:29 GMT</lastBuildDate><atom:link href="https://blog.yogeshchavan.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Build a Task Management App Using Next.js 16 and Prisma 7]]></title><description><![CDATA[In this tutorial, you will build a Task Management App using Next.js 16 and Prisma 7 from scratch.
By creating this app, you will learn:

How to set up Prisma 7 with the new Rust-free architecture

How to configure a database with Prisma's driver ada...]]></description><link>https://blog.yogeshchavan.dev/how-to-build-a-task-management-app-using-nextjs-16-and-prisma-7</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/how-to-build-a-task-management-app-using-nextjs-16-and-prisma-7</guid><category><![CDATA[Next.js]]></category><category><![CDATA[React]]></category><category><![CDATA[prisma]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Tue, 16 Dec 2025 09:08:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765876042701/ef8b2bdc-6a5e-4c1e-9d35-ea9fef9b076f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, you will build a Task Management App using Next.js 16 and Prisma 7 from scratch.</p>
<p>By creating this app, you will learn:</p>
<ol>
<li><p>How to set up Prisma 7 with the new Rust-free architecture</p>
</li>
<li><p>How to configure a database with Prisma's driver adapter</p>
</li>
<li><p>How to perform CRUD operations using Server Actions</p>
</li>
<li><p>How to use the Next.js App Router for building full-stack applications</p>
</li>
<li><p>How to create and run database migrations</p>
</li>
<li><p>How to structure a Next.js project with Prisma ORM</p>
</li>
</ol>
<p>and much more.</p>
<p>Prisma 7 introduces a major architectural shift – it's now "Rust-free" and requires the use of driver adapters for all database connections. This makes Prisma lighter, faster, and more compatible with modern JavaScript runtimes.</p>
<blockquote>
<p><strong>Note:</strong> This tutorial uses Prisma 7, which has breaking changes from earlier versions. If you're upgrading from Prisma 6, be aware that the setup process is different.</p>
</blockquote>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you begin, make sure you have:</p>
<ul>
<li><p>Node.js 20.9 or higher installed</p>
</li>
<li><p>Basic knowledge of React and Next.js</p>
</li>
<li><p>Familiarity with TypeScript (we'll use TypeScript throughout)</p>
</li>
</ul>
<blockquote>
<p>If you're new to Next.js and want to learn it from scratch from basics to advanced? <a target="_blank" href="https://courses.yogeshchavan.dev/mastering-next-js-15-from-basics-to-advanced">Check out this course</a>.</p>
<p>If you're new to TypeScript + React, <a target="_blank" href="https://www.freecodecamp.org/news/use-typescript-with-react/">check out my this article</a>.</p>
</blockquote>
<h2 id="heading-initial-setup">Initial Setup</h2>
<p>Create a new Next.js project using <code>create-next-app</code>:</p>
<pre><code class="lang-bash">npx create-next-app@16.0.10 prisma-nextjs-task-management-app
</code></pre>
<p>Here, we're specifying the exact and latest version of Next.js (at the time of writing this tutorial), which is 16.0.10. Therefore, the code in this tutorial will always work, even if a newer version with breaking changes is released in the future.</p>
<p>So you will not have any issues following this tutorial.</p>
<p>You can also use:</p>
<pre><code class="lang-bash">npx create-next-app@latest prisma-nextjs-task-management-app
</code></pre>
<p>to always use the latest available Next.js version. However, for this tutorial, we will not use this command.</p>
<p>When prompted, type <code>y</code> to say <code>yes</code> to proceed with installation and press the enter key to go with recommended defaults, as can be seen below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765851438779/6375997f-e308-4599-8904-0877fc9035fd.png" alt class="image--center mx-auto" /></p>
<p>By going with the recommended default settings, we're going with these default settings:</p>
<pre><code class="lang-bash">✔ Would you like to use TypeScript? Yes
✔ Would you like to use ESLint? Yes
✔ Would you like to use Tailwind CSS? Yes
✔ Would you like your code inside a `src/` directory? No
✔ Would you like to use App Router? Yes
✔ Would you like to use Turbopack <span class="hljs-keyword">for</span> `next dev`? Yes
✔ Would you like to customize the import <span class="hljs-built_in">alias</span>? No
</code></pre>
<p>Now, navigate into the project directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> prisma-nextjs-task-management-app
</code></pre>
<p>Now install the necessary dependencies for Prisma 7:</p>
<pre><code class="lang-bash">npm install prisma @types/better-sqlite3 --save-dev
npm install @prisma/client @prisma/adapter-better-sqlite3 dotenv
</code></pre>
<p>Let's understand what each package does:</p>
<ul>
<li><p><code>prisma</code> – The Prisma CLI for migrations, schema management, and client generation</p>
</li>
<li><p><code>@prisma/client</code> – The Prisma Client library for querying your database</p>
</li>
<li><p><code>@prisma/adapter-better-sqlite3</code> – The driver adapter that connects Prisma Client to SQLite (required in Prisma 7)</p>
</li>
<li><p><code>@types/better-sqlite3</code> – TypeScript type definitions for better-sqlite3</p>
</li>
<li><p><code>dotenv</code> – Loads environment variables from your .env file</p>
</li>
</ul>
<p>For this tutorial, we're using a SQLite database, so it's easier to understand the basics of Prisma and Next.js.</p>
<p>Note that the code you write to interact with the database and used in this tutorial will not change even if you use either SQLite/PostgreSQL/MySQL or any other database. That's the power of using an ORM like Prisma ORM.</p>
<p>However, if you want to learn how to work with a <a target="_blank" href="https://neon.com/">hosted PostgreSQL database</a>, check out my course where we built a <a target="_blank" href="https://courses.yogeshchavan.dev/mastering-next-js-15-from-basics-to-advanced">complete Event Management App From Scratch</a>.</p>
<h2 id="heading-how-to-initialize-prisma">How to Initialize Prisma</h2>
<p>Run the following command to initialize Prisma with SQLite:</p>
<pre><code class="lang-bash">npx prisma init --datasource-provider sqlite --output ../generated/prisma
</code></pre>
<p>This command creates:</p>
<ol>
<li><p>A <code>prisma</code> folder with a <code>schema.prisma</code> file</p>
</li>
<li><p>A <code>.env</code> file with a <code>DATABASE_URL</code> environment variable</p>
</li>
<li><p>A <code>prisma.config.ts</code> file for Prisma configuration</p>
</li>
</ol>
<h2 id="heading-how-to-configure-the-prisma-config-file">How to Configure the Prisma Config File</h2>
<p>Prisma 7 introduces a new configuration file called <code>prisma.config.ts</code>. This file separates your project configuration from your schema definition. Update or create the <code>prisma.config.ts</code> file in your project root with the following content:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-string">'dotenv/config'</span>
<span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'prisma/config'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  schema: <span class="hljs-string">'prisma/schema.prisma'</span>,
  datasource: {
    url: process.env.DATABASE_URL || <span class="hljs-string">'file:./prisma/dev.db'</span>,
  },
})
</code></pre>
<p>Here, we're importing <code>dotenv/config</code> to load environment variables and define the schema location and database URL.</p>
<p>Note that we're giving the path of <code>./prisma/</code> in the above file, because the <code>dev.db</code> file needs to be created inside the <code>prisma</code> folder, so everything will work as expected.</p>
<h2 id="heading-how-to-set-up-the-database-schema">How to Set Up the Database Schema</h2>
<p>Open the <code>prisma/schema.prisma</code> file and replace its contents with the following:</p>
<pre><code class="lang-bash">generator client {
  provider = <span class="hljs-string">"prisma-client"</span>
  output   = <span class="hljs-string">"../generated/prisma"</span>
}

datasource db {
  provider = <span class="hljs-string">"sqlite"</span>
}

model Task {
  id          Int      @id @default(autoincrement())
  title       String
  description String?
  completed   Boolean  @default(<span class="hljs-literal">false</span>)
  priority    String   @default(<span class="hljs-string">"medium"</span>)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}
</code></pre>
<p>Let's understand what we've defined here:</p>
<p><strong>Generator block:</strong></p>
<ul>
<li><p><code>provider = "prisma-client"</code> – Uses the new Prisma 7 client generator (not <code>prisma-client-js</code> used in version 6 of Prisma)</p>
</li>
<li><p><code>output = "../generated/prisma"</code> – Specifies where the generated client files will be placed</p>
</li>
</ul>
<p><strong>Datasource block:</strong></p>
<ul>
<li><p><code>provider = "sqlite"</code> – Specifies SQLite as our database</p>
</li>
<li><p>Note: In Prisma 7, the <code>url</code> is no longer in the schema file – it's in <code>prisma.config.ts</code></p>
</li>
</ul>
<p><strong>Task model:</strong></p>
<ul>
<li><p><code>id</code> – Auto-incrementing primary key</p>
</li>
<li><p><code>title</code> – Required string for the task title</p>
</li>
<li><p><code>description</code> – Optional string for task description</p>
</li>
<li><p><code>completed</code> – Boolean flag with default value <code>false</code></p>
</li>
<li><p><code>priority</code> – String field with default value "medium"</p>
</li>
<li><p><code>createdAt</code> – Timestamp set automatically when a task is created</p>
</li>
<li><p><code>updatedAt</code> – Timestamp updated automatically when a task is modified</p>
</li>
</ul>
<h2 id="heading-how-to-configure-the-path-alias">How to Configure the Path Alias</h2>
<p>Make sure your <code>tsconfig.json</code> has the proper path alias for imports. It should include:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"compilerOptions"</span>: {
    <span class="hljs-attr">"paths"</span>: {
      <span class="hljs-attr">"@/*"</span>: [<span class="hljs-string">"./*"</span>]
    }
  }
}
</code></pre>
<p>This is usually set up by default with <code>create-next-app</code>.</p>
<h2 id="heading-how-to-run-your-first-migration">How to Run Your First Migration</h2>
<p>Now, let's create the database tables based on our schema. Run:</p>
<pre><code class="lang-bash">npx prisma migrate dev --name init
</code></pre>
<p>This command:</p>
<ol>
<li><p>Creates the SQLite database file (<code>dev.db</code>) in the <code>prisma</code> folder</p>
</li>
<li><p>Creates a new migration in <code>prisma/migrations/</code></p>
</li>
<li><p>Applies the migration to your database</p>
</li>
<li><p>Generates the Prisma Client</p>
</li>
</ol>
<p>You should see output similar to:</p>
<pre><code class="lang-bash">Environment variables loaded from .env
Prisma schema loaded from prisma/schema.prisma
Datasource <span class="hljs-string">"db"</span>: SQLite database <span class="hljs-string">"dev.db"</span> at <span class="hljs-string">"file:./dev.db"</span>

SQLite database dev.db created at file:./dev.db

Applying migration `20241215_init`

The following migration(s) have been created and applied from new schema changes:

migrations/
  └─ 20241215_init/
    └─ migration.sql
</code></pre>
<p>Now generate the Prisma Client:</p>
<pre><code class="lang-bash">npx prisma generate
</code></pre>
<p>Prisma Client is needed because that's the one that will interact with your database which can be SQLite/PostgreSQL/MySQL.</p>
<h2 id="heading-how-to-create-the-prisma-client-instance">How to Create the Prisma Client Instance</h2>
<p>In Prisma 7, you need to use a driver adapter to connect to your database. Create a new file called <code>lib/prisma.ts</code>:</p>
<pre><code class="lang-bash">mkdir lib
</code></pre>
<p>Then create <code>lib/prisma.ts</code> with the following content:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> <span class="hljs-string">'dotenv/config'</span>
<span class="hljs-keyword">import</span> { PrismaBetterSqlite3 } <span class="hljs-keyword">from</span> <span class="hljs-string">'@prisma/adapter-better-sqlite3'</span>
<span class="hljs-keyword">import</span> { PrismaClient } <span class="hljs-keyword">from</span> <span class="hljs-string">'../generated/prisma/client'</span>

<span class="hljs-keyword">const</span> connectionString = process.env.DATABASE_URL || <span class="hljs-string">'file:./prisma/dev.db'</span>

<span class="hljs-keyword">const</span> adapter = <span class="hljs-keyword">new</span> PrismaBetterSqlite3({
  url: connectionString,
})

<span class="hljs-keyword">const</span> globalForPrisma = globalThis <span class="hljs-keyword">as</span> unknown <span class="hljs-keyword">as</span> {
  prisma: PrismaClient | <span class="hljs-literal">undefined</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> prisma =
  globalForPrisma.prisma ??
  <span class="hljs-keyword">new</span> PrismaClient({
    adapter,
  })

<span class="hljs-keyword">if</span> (process.env.NODE_ENV !== <span class="hljs-string">'production'</span>) {
  globalForPrisma.prisma = prisma
}
</code></pre>
<p>Let's break down what this code does:</p>
<ol>
<li><p><strong>Import the adapter:</strong> We import <code>PrismaBetterSqlite3</code> from <code>@prisma/adapter-better-sqlite3</code>. This is required in Prisma 7 for all database connections.</p>
</li>
<li><p><strong>Create the adapter instance:</strong> We instantiate the adapter with our database URL.</p>
</li>
<li><p><strong>Singleton pattern:</strong> We use the global object to store a single Prisma Client instance. This prevents creating multiple connections during development when hot reloading occurs.</p>
</li>
<li><p><strong>Pass the adapter:</strong> The adapter is passed to <code>PrismaClient</code> in the constructor.</p>
</li>
</ol>
<h2 id="heading-how-to-create-server-actions-for-crud-operations">How to Create Server Actions for CRUD Operations</h2>
<p>Next.js Server Actions allow us to write server-side code that can be called directly from our components. Create a new file called <code>app/actions.ts</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-string">'use server'</span>

<span class="hljs-keyword">import</span> { prisma } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/lib/prisma'</span>
<span class="hljs-keyword">import</span> { revalidatePath } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/cache'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">type</span> TaskFormData = {
  title: <span class="hljs-built_in">string</span>
  description?: <span class="hljs-built_in">string</span>
  priority: <span class="hljs-built_in">string</span>
}

<span class="hljs-comment">// Create a new task</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createTask</span>(<span class="hljs-params">formData: FormData</span>) </span>{
  <span class="hljs-keyword">const</span> title = formData.get(<span class="hljs-string">'title'</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>
  <span class="hljs-keyword">const</span> description = formData.get(<span class="hljs-string">'description'</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>
  <span class="hljs-keyword">const</span> priority = formData.get(<span class="hljs-string">'priority'</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>

  <span class="hljs-keyword">if</span> (!title || title.trim() === <span class="hljs-string">''</span>) {
    <span class="hljs-keyword">return</span> { error: <span class="hljs-string">'Title is required'</span> }
  }

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> prisma.task.create({
      data: {
        title: title.trim(),
        description: description?.trim() || <span class="hljs-literal">null</span>,
        priority: priority || <span class="hljs-string">'medium'</span>,
      },
    })

    revalidatePath(<span class="hljs-string">'/'</span>)
    <span class="hljs-keyword">return</span> { success: <span class="hljs-literal">true</span> }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Failed to create task:'</span>, error)
    <span class="hljs-keyword">return</span> { error: <span class="hljs-string">'Failed to create task'</span> }
  }
}

<span class="hljs-comment">// Get all tasks</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTasks</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> tasks = <span class="hljs-keyword">await</span> prisma.task.findMany({
      orderBy: {
        createdAt: <span class="hljs-string">'desc'</span>,
      },
    })
    <span class="hljs-keyword">return</span> tasks
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Failed to fetch tasks:'</span>, error)
    <span class="hljs-keyword">return</span> []
  }
}

<span class="hljs-comment">// Toggle task completion status</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toggleTaskComplete</span>(<span class="hljs-params">id: <span class="hljs-built_in">number</span></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> task = <span class="hljs-keyword">await</span> prisma.task.findUnique({
      where: { id },
    })

    <span class="hljs-keyword">if</span> (!task) {
      <span class="hljs-keyword">return</span> { error: <span class="hljs-string">'Task not found'</span> }
    }

    <span class="hljs-keyword">await</span> prisma.task.update({
      where: { id },
      data: {
        completed: !task.completed,
      },
    })

    revalidatePath(<span class="hljs-string">'/'</span>)
    <span class="hljs-keyword">return</span> { success: <span class="hljs-literal">true</span> }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Failed to toggle task:'</span>, error)
    <span class="hljs-keyword">return</span> { error: <span class="hljs-string">'Failed to toggle task'</span> }
  }
}

<span class="hljs-comment">// Update a task</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateTask</span>(<span class="hljs-params">id: <span class="hljs-built_in">number</span>, formData: FormData</span>) </span>{
  <span class="hljs-keyword">const</span> title = formData.get(<span class="hljs-string">'title'</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>
  <span class="hljs-keyword">const</span> description = formData.get(<span class="hljs-string">'description'</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>
  <span class="hljs-keyword">const</span> priority = formData.get(<span class="hljs-string">'priority'</span>) <span class="hljs-keyword">as</span> <span class="hljs-built_in">string</span>

  <span class="hljs-keyword">if</span> (!title || title.trim() === <span class="hljs-string">''</span>) {
    <span class="hljs-keyword">return</span> { error: <span class="hljs-string">'Title is required'</span> }
  }

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> prisma.task.update({
      where: { id },
      data: {
        title: title.trim(),
        description: description?.trim() || <span class="hljs-literal">null</span>,
        priority: priority || <span class="hljs-string">'medium'</span>,
      },
    })

    revalidatePath(<span class="hljs-string">'/'</span>)
    <span class="hljs-keyword">return</span> { success: <span class="hljs-literal">true</span> }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Failed to update task:'</span>, error)
    <span class="hljs-keyword">return</span> { error: <span class="hljs-string">'Failed to update task'</span> }
  }
}

<span class="hljs-comment">// Delete a task</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleteTask</span>(<span class="hljs-params">id: <span class="hljs-built_in">number</span></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> prisma.task.delete({
      where: { id },
    })

    revalidatePath(<span class="hljs-string">'/'</span>)
    <span class="hljs-keyword">return</span> { success: <span class="hljs-literal">true</span> }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Failed to delete task:'</span>, error)
    <span class="hljs-keyword">return</span> { error: <span class="hljs-string">'Failed to delete task'</span> }
  }
}
</code></pre>
<p>Let's understand what each function does:</p>
<p><strong>createTask:</strong> Uses <code>prisma.task.create()</code> to insert a new task into the database. We extract form data, validate the title, and return appropriate responses.</p>
<p><strong>getTasks:</strong> Uses <code>prisma.task.findMany()</code> to retrieve all tasks, ordered by creation date in descending order.</p>
<p><strong>toggleTaskComplete:</strong> First finds the task using <code>prisma.task.findUnique()</code>, then uses <code>prisma.task.update()</code> to toggle the <code>completed</code> field.</p>
<p><strong>updateTask:</strong> Uses <code>prisma.task.update()</code> to modify an existing task's title, description, and priority.</p>
<p><strong>deleteTask:</strong> Uses <code>prisma.task.delete()</code> to remove a task from the database.</p>
<p>Note that we call <code>revalidatePath('/')</code> after each mutation to automatically refresh the page data, so we don't need to reload the page to see the added/updated/deleted data.</p>
<h2 id="heading-how-to-create-the-task-components">How to Create the Task Components</h2>
<p>Now let's create the UI components. First, create a components folder:</p>
<pre><code class="lang-bash">mkdir components
</code></pre>
<h3 id="heading-taskform-component">TaskForm Component</h3>
<p>Create <code>components/TaskForm.tsx</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-string">'use client'</span>

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> { createTask, updateTask } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/app/actions'</span>

type TaskFormProps = {
  task?: {
    <span class="hljs-attr">id</span>: number
    <span class="hljs-attr">title</span>: string
    <span class="hljs-attr">description</span>: string | <span class="hljs-literal">null</span>
    <span class="hljs-attr">priority</span>: string
  }
  onSuccess?: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">void</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TaskForm</span>(<span class="hljs-params">{ task, onSuccess }: TaskFormProps</span>) </span>{
  <span class="hljs-keyword">const</span> [error, setError] = useState&lt;string | <span class="hljs-literal">null</span>&gt;(<span class="hljs-literal">null</span>)
  <span class="hljs-keyword">const</span> [isSubmitting, setIsSubmitting] = useState(<span class="hljs-literal">false</span>)

  <span class="hljs-keyword">const</span> isEditing = !!task

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleSubmit</span>(<span class="hljs-params">formData: FormData</span>) </span>{
    setError(<span class="hljs-literal">null</span>)
    setIsSubmitting(<span class="hljs-literal">true</span>)

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> result = isEditing
        ? <span class="hljs-keyword">await</span> updateTask(task.id, formData)
        : <span class="hljs-keyword">await</span> createTask(formData)

      <span class="hljs-keyword">if</span> (result.error) {
        setError(result.error)
      } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (onSuccess) {
        onSuccess()
      }
    } <span class="hljs-keyword">catch</span> (err) {
      setError(<span class="hljs-string">'Something went wrong'</span>)
    } <span class="hljs-keyword">finally</span> {
      setIsSubmitting(<span class="hljs-literal">false</span>)
    }
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">{handleSubmit}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-4"</span>&gt;</span>
      {error &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded"</span>&gt;</span>
          {error}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"title"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-sm font-medium text-gray-700 mb-1"</span>&gt;</span>
          Title *
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">id</span>=<span class="hljs-string">"title"</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"title"</span>
          <span class="hljs-attr">defaultValue</span>=<span class="hljs-string">{task?.title</span> || ''}
          <span class="hljs-attr">required</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter task title"</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-sm font-medium text-gray-700 mb-1"</span>&gt;</span>
          Description
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
          <span class="hljs-attr">id</span>=<span class="hljs-string">"description"</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span>
          <span class="hljs-attr">defaultValue</span>=<span class="hljs-string">{task?.description</span> || ''}
          <span class="hljs-attr">rows</span>=<span class="hljs-string">{3}</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter task description (optional)"</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"priority"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-sm font-medium text-gray-700 mb-1"</span>&gt;</span>
          Priority
        <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">select</span>
          <span class="hljs-attr">id</span>=<span class="hljs-string">"priority"</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"priority"</span>
          <span class="hljs-attr">defaultValue</span>=<span class="hljs-string">{task?.priority</span> || '<span class="hljs-attr">medium</span>'}
          <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"low"</span>&gt;</span>Low<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"medium"</span>&gt;</span>Medium<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"high"</span>&gt;</span>High<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
        <span class="hljs-attr">disabled</span>=<span class="hljs-string">{isSubmitting}</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"</span>
      &gt;</span>
        {isSubmitting ? 'Saving...' : isEditing ? 'Update Task' : 'Add Task'}
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  )
}
</code></pre>
<p>This component handles both creating new tasks and editing existing ones. If a <code>task</code> prop is passed, it pre-fills the form and uses the <code>updateTask</code> action. Otherwise, it uses the <code>createTask</code> action.</p>
<h3 id="heading-taskitem-component">TaskItem Component</h3>
<p>Create <code>components/TaskItem.tsx</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> { deleteTask, toggleTaskComplete } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/app/actions"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> TaskForm <span class="hljs-keyword">from</span> <span class="hljs-string">"./TaskForm"</span>;

type Task = {
  <span class="hljs-attr">id</span>: number;
  title: string;
  description: string | <span class="hljs-literal">null</span>;
  completed: boolean;
  priority: string;
  createdAt: <span class="hljs-built_in">Date</span>;
  updatedAt: <span class="hljs-built_in">Date</span>;
};

type TaskItemProps = {
  <span class="hljs-attr">task</span>: Task;
};

<span class="hljs-keyword">const</span> priorityColors = {
  <span class="hljs-attr">low</span>: <span class="hljs-string">"bg-green-100 text-green-800"</span>,
  <span class="hljs-attr">medium</span>: <span class="hljs-string">"bg-yellow-100 text-yellow-800"</span>,
  <span class="hljs-attr">high</span>: <span class="hljs-string">"bg-red-100 text-red-800"</span>,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TaskItem</span>(<span class="hljs-params">{ task }: TaskItemProps</span>) </span>{
  <span class="hljs-keyword">const</span> [isEditing, setIsEditing] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [isDeleting, setIsDeleting] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleToggle</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">await</span> toggleTaskComplete(task.id);
  }

  <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleDelete</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (confirm(<span class="hljs-string">"Are you sure you want to delete this task?"</span>)) {
      setIsDeleting(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">await</span> deleteTask(task.id);
    }
  }

  <span class="hljs-keyword">if</span> (isEditing) {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white p-4 rounded-lg shadow-md border border-gray-200"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-between items-center mb-4"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg font-medium"</span>&gt;</span>Edit Task<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsEditing(false)}
            className="text-gray-500 hover:text-gray-700"
          &gt;
            Cancel
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">TaskForm</span> <span class="hljs-attr">task</span>=<span class="hljs-string">{task}</span> <span class="hljs-attr">onSuccess</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsEditing(false)} /&gt;
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
  }

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">bg-white</span> <span class="hljs-attr">p-4</span> <span class="hljs-attr">rounded-lg</span> <span class="hljs-attr">shadow-md</span> <span class="hljs-attr">border</span> <span class="hljs-attr">border-gray-200</span> <span class="hljs-attr">transition-opacity</span> ${
        <span class="hljs-attr">task.completed</span> ? "<span class="hljs-attr">opacity-60</span>" <span class="hljs-attr">:</span> ""
      }`}
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-start gap-3"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
          <span class="hljs-attr">checked</span>=<span class="hljs-string">{task.completed}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleToggle}</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-1 h-5 w-5 rounded border-gray-300 text-blue-600 focus:ring-blue-500 cursor-pointer"</span>
        /&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex-1"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center gap-2 mb-1"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">font-medium</span> ${
                <span class="hljs-attr">task.completed</span> ? "<span class="hljs-attr">line-through</span> <span class="hljs-attr">text-gray-500</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">text-gray-900</span>"
              }`}
            &gt;</span>
              {task.title}
            <span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">px-2</span> <span class="hljs-attr">py-0.5</span> <span class="hljs-attr">text-xs</span> <span class="hljs-attr">font-medium</span> <span class="hljs-attr">rounded-full</span> ${
                <span class="hljs-attr">priorityColors</span>[<span class="hljs-attr">task.priority</span> <span class="hljs-attr">as</span> <span class="hljs-attr">keyof</span> <span class="hljs-attr">typeof</span> <span class="hljs-attr">priorityColors</span>]
              }`}
            &gt;</span>
              {task.priority}
            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          {task.description &amp;&amp; (
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 text-sm mb-2"</span>&gt;</span>{task.description}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          )}

          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xs text-gray-400"</span>&gt;</span>
            Created: {new Date(task.createdAt).toISOString().split("T")[0]}
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsEditing(true)}
            className="text-blue-600 hover:text-blue-800 text-sm font-medium"
          &gt;
            Edit
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleDelete}</span>
            <span class="hljs-attr">disabled</span>=<span class="hljs-string">{isDeleting}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"text-red-600 hover:text-red-800 text-sm font-medium disabled:opacity-50"</span>
          &gt;</span>
            {isDeleting ? "Deleting..." : "Delete"}
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>This component displays a single task with:</p>
<ul>
<li><p>A checkbox to toggle completion status</p>
</li>
<li><p>The task title with strikethrough styling when completed</p>
</li>
<li><p>A priority badge with color coding</p>
</li>
<li><p>Optional description</p>
</li>
<li><p>Creation date</p>
</li>
<li><p>Edit and Delete buttons</p>
</li>
</ul>
<p>When editing, it renders the <code>TaskForm</code> component with the current task data.</p>
<h3 id="heading-tasklist-component">TaskList Component</h3>
<p>Create <code>components/TaskList.tsx</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { getTasks } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/app/actions'</span>
<span class="hljs-keyword">import</span> TaskItem <span class="hljs-keyword">from</span> <span class="hljs-string">'./TaskItem'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TaskList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> tasks = <span class="hljs-keyword">await</span> getTasks()

  <span class="hljs-keyword">if</span> (tasks.length === <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center py-12"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 text-lg"</span>&gt;</span>No tasks yet. Add your first task above!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    )
  }

  <span class="hljs-keyword">const</span> completedTasks = tasks.filter(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> task.completed)
  <span class="hljs-keyword">const</span> pendingTasks = tasks.filter(<span class="hljs-function">(<span class="hljs-params">task</span>) =&gt;</span> !task.completed)

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-6"</span>&gt;</span>
      {pendingTasks.length &gt; 0 &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg font-semibold text-gray-700 mb-3"</span>&gt;</span>
            Pending Tasks ({pendingTasks.length})
          <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-3"</span>&gt;</span>
            {pendingTasks.map((task) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">TaskItem</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{task.id}</span> <span class="hljs-attr">task</span>=<span class="hljs-string">{task}</span> /&gt;</span>
            ))}
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}

      {completedTasks.length &gt; 0 &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg font-semibold text-gray-700 mb-3"</span>&gt;</span>
            Completed Tasks ({completedTasks.length})
          <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-3"</span>&gt;</span>
            {completedTasks.map((task) =&gt; (
              <span class="hljs-tag">&lt;<span class="hljs-name">TaskItem</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{task.id}</span> <span class="hljs-attr">task</span>=<span class="hljs-string">{task}</span> /&gt;</span>
            ))}
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>This is a Server Component that fetches all tasks and renders them. It separates tasks into pending and completed sections for better organization.</p>
<h3 id="heading-addtaskbutton-component">AddTaskButton Component</h3>
<p>Create <code>components/AddTaskButton.tsx</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-string">'use client'</span>

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> TaskForm <span class="hljs-keyword">from</span> <span class="hljs-string">'./TaskForm'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AddTaskButton</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isOpen, setIsOpen] = useState(<span class="hljs-literal">false</span>)

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {!isOpen ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsOpen(true)}
          className="w-full bg-blue-600 text-white py-3 px-4 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors font-medium"
        &gt;
          + Add New Task
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white p-6 rounded-lg shadow-md border border-gray-200"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-between items-center mb-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold text-gray-800"</span>&gt;</span>Add New Task<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsOpen(false)}
              className="text-gray-500 hover:text-gray-700 text-2xl leading-none"
            &gt;
              ×
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">TaskForm</span> <span class="hljs-attr">onSuccess</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsOpen(false)} /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>This component toggles between showing an "Add New Task" button and the task form.</p>
<h2 id="heading-how-to-create-the-main-page">How to Create the Main Page</h2>
<p>Now let's update the main page to display our task management interface. Replace the contents of <code>app/page.tsx</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> AddTaskButton <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/AddTaskButton'</span>
<span class="hljs-keyword">import</span> TaskList <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/TaskList'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"min-h-screen bg-gray-100 py-8"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-2xl mx-auto px-4"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center mb-8"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl font-bold text-gray-800 mb-2"</span>&gt;</span>Task Management<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>Organize your tasks efficiently with Prisma &amp; Next.js<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">AddTaskButton</span> /&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span>
            <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>
              &lt;<span class="hljs-attr">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center py-12"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 mt-2"</span>&gt;</span>Loading tasks...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            }
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">TaskList</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  )
}
</code></pre>
<p>We wrap <code>TaskList</code> in a <code>Suspense</code> boundary to show a loading state while the tasks are being fetched.</p>
<h2 id="heading-how-to-run-the-application">How to Run the Application</h2>
<p>Now you're ready to run the application. Start the development server:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Open your browser and navigate to <code>http://localhost:3000</code>. You should see the task management application screen as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765862695352/d7e627c8-d61a-43c3-910a-a5cc7aa4ad97.png" alt class="image--center mx-auto" /></p>
<p>Try the following:</p>
<ol>
<li><p>Click "Add New Task" to open the form</p>
</li>
<li><p>Enter a title like "Learn Prisma 7"</p>
</li>
<li><p>Add a description (optional)</p>
</li>
<li><p>Select a priority level</p>
</li>
<li><p>Click "Add Task"</p>
</li>
</ol>
<p>Your task should appear in the list!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765881655515/f99bfe44-e475-42a4-bce2-4979b6141fa9.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765864297488/6327a791-88ee-4936-a3aa-3f30142c2e4d.png" alt class="image--center mx-auto" /></p>
<p>Now you can:</p>
<ul>
<li>Click "Edit" to modify a task</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765873135104/1d79528d-2882-4462-b279-cab2bd830d82.gif" alt class="image--center mx-auto" /></p>
<ul>
<li>Click the checkbox to mark tasks as complete</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765873375957/5e36b564-46d1-44ef-a235-8d93c770d10f.gif" alt class="image--center mx-auto" /></p>
<ul>
<li>Click "Delete" to delete a task</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765873517663/a2e8bfc9-58fb-4919-a03e-f621b40ece82.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-how-to-explore-your-data-with-prisma-studio">How to Explore Your Data with Prisma Studio</h2>
<p>Prisma comes with a built-in GUI for exploring and editing your database. Run:</p>
<pre><code class="lang-bash">npx prisma studio
</code></pre>
<p>This opens Prisma Studio in your browser at <a target="_blank" href="http://localhost:51212">http://localhost:51212</a>. You can:</p>
<ul>
<li><p>View all your tasks in a table format</p>
</li>
<li><p>Add new records directly</p>
</li>
<li><p>Edit existing records</p>
</li>
<li><p>Delete records</p>
</li>
<li><p>Filter and sort data</p>
</li>
</ul>
<p>Make sure to add some tasks from the application to see them in the studio, as we deleted the first task above.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765865372864/299fe008-03ec-4f03-ae24-6784be646857.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-understanding-prisma-7s-new-architecture">Understanding Prisma 7's New Architecture</h2>
<p>Prisma 7 introduces several important changes that you should understand:</p>
<h3 id="heading-driver-adapters">Driver Adapters</h3>
<p>In previous versions, Prisma used Rust-based engines for database connections. Prisma 7 moves to a "Rust-free" architecture that uses JavaScript driver adapters instead.</p>
<p>For SQLite, we use <code>@prisma/adapter-better-sqlite3</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { PrismaBetterSqlite3 } <span class="hljs-keyword">from</span> <span class="hljs-string">'@prisma/adapter-better-sqlite3'</span>

<span class="hljs-keyword">const</span> adapter = <span class="hljs-keyword">new</span> PrismaBetterSqlite3({
  url: <span class="hljs-string">'file:./prisma/dev.db'</span>,
})

<span class="hljs-keyword">const</span> prisma = <span class="hljs-keyword">new</span> PrismaClient({ adapter })
</code></pre>
<p>This approach offers several benefits:</p>
<ul>
<li><p>Smaller package size (no Rust binaries)</p>
</li>
<li><p>Better compatibility with edge runtimes</p>
</li>
<li><p>Faster cold starts</p>
</li>
<li><p>More flexible database driver options</p>
</li>
</ul>
<h3 id="heading-new-generator-provider">New Generator Provider</h3>
<p>The generator provider has changed from <code>prisma-client-js</code> to <code>prisma-client</code>:</p>
<pre><code class="lang-bash">generator client {
  provider = <span class="hljs-string">"prisma-client"</span>  // New <span class="hljs-keyword">in</span> Prisma 7
  output   = <span class="hljs-string">"../generated/prisma"</span>
}
</code></pre>
<h3 id="heading-configuration-file">Configuration File</h3>
<p>The new <code>prisma.config.ts</code> file centralizes the configuration that was previously spread across multiple files:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { defineConfig } <span class="hljs-keyword">from</span> <span class="hljs-string">'prisma/config'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> defineConfig({
  schema: <span class="hljs-string">'prisma/schema.prisma'</span>,
  datasource: {
    url: process.env.DATABASE_URL,
  },
})
</code></pre>
<h2 id="heading-adding-more-features">Adding More Features</h2>
<p>Let's extend our application with a few more useful features.</p>
<h3 id="heading-task-filtering">Task Filtering</h3>
<p>Add a filter component to show tasks by priority. Create <code>components/TaskFilter.tsx</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-string">'use client'</span>

<span class="hljs-keyword">import</span> { useRouter, useSearchParams } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/navigation'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TaskFilter</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> router = useRouter()
  <span class="hljs-keyword">const</span> searchParams = useSearchParams()
  <span class="hljs-keyword">const</span> currentFilter = searchParams.get(<span class="hljs-string">'priority'</span>) || <span class="hljs-string">'all'</span>

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleFilterChange</span>(<span class="hljs-params">priority: string</span>) </span>{
    <span class="hljs-keyword">const</span> params = <span class="hljs-keyword">new</span> URLSearchParams(searchParams)
    <span class="hljs-keyword">if</span> (priority === <span class="hljs-string">'all'</span>) {
      params.delete(<span class="hljs-string">'priority'</span>)
    } <span class="hljs-keyword">else</span> {
      params.set(<span class="hljs-string">'priority'</span>, priority)
    }
    router.push(<span class="hljs-string">`/?<span class="hljs-subst">${params.toString()}</span>`</span>)
  }

  <span class="hljs-keyword">const</span> filters = [<span class="hljs-string">'all'</span>, <span class="hljs-string">'high'</span>, <span class="hljs-string">'medium'</span>, <span class="hljs-string">'low'</span>]

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex gap-2 justify-center"</span>&gt;</span>
      {filters.map((filter) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">key</span>=<span class="hljs-string">{filter}</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleFilterChange(filter)}
          className={`px-4 py-2 rounded-full text-sm font-medium transition-colors ${
            currentFilter === filter
              ? 'bg-blue-600 text-white'
              : 'bg-gray-200 text-gray-700 hover:bg-gray-300'
          }`}
        &gt;
          {filter.charAt(0).toUpperCase() + filter.slice(1)}
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>Update the <code>getTasks</code> function in <code>app/actions.ts</code> to support filtering:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getTasks</span>(<span class="hljs-params">priority?: <span class="hljs-built_in">string</span></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> where = priority &amp;&amp; priority !== <span class="hljs-string">'all'</span> ? { priority } : {}

    <span class="hljs-keyword">const</span> tasks = <span class="hljs-keyword">await</span> prisma.task.findMany({
      where,
      orderBy: {
        createdAt: <span class="hljs-string">'desc'</span>,
      },
    })
    <span class="hljs-keyword">return</span> tasks
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Failed to fetch tasks:'</span>, error)
    <span class="hljs-keyword">return</span> []
  }
}
</code></pre>
<h3 id="heading-task-statistics">Task Statistics</h3>
<p>Create a component to display task statistics. Create <code>components/TaskStats.tsx</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { prisma } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/lib/prisma'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TaskStats</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [total, completed, highPriority] = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all([
    prisma.task.count(),
    prisma.task.count({ <span class="hljs-attr">where</span>: { <span class="hljs-attr">completed</span>: <span class="hljs-literal">true</span> } }),
    prisma.task.count({ <span class="hljs-attr">where</span>: { <span class="hljs-attr">priority</span>: <span class="hljs-string">'high'</span>, <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span> } }),
  ])

  <span class="hljs-keyword">const</span> completionRate = total &gt; <span class="hljs-number">0</span> ? <span class="hljs-built_in">Math</span>.round((completed / total) * <span class="hljs-number">100</span>) : <span class="hljs-number">0</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid grid-cols-3 gap-4 mb-6"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white p-4 rounded-lg shadow-sm text-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-bold text-gray-800"</span>&gt;</span>{total}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm text-gray-500"</span>&gt;</span>Total Tasks<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white p-4 rounded-lg shadow-sm text-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-bold text-green-600"</span>&gt;</span>{completionRate}%<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm text-gray-500"</span>&gt;</span>Completed<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white p-4 rounded-lg shadow-sm text-center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-bold text-red-600"</span>&gt;</span>{highPriority}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm text-gray-500"</span>&gt;</span>High Priority<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>Now, use this component in the <code>app/page.tsx</code> file after the <code>header</code> tag for a quick overview of your tasks:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> AddTaskButton <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/AddTaskButton"</span>;
<span class="hljs-keyword">import</span> TaskList <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/TaskList"</span>;
<span class="hljs-keyword">import</span> TaskStats <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/TaskStats"</span>;
<span class="hljs-keyword">import</span> { Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"min-h-screen bg-gray-100 py-8"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-2xl mx-auto px-4"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center mb-8"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl font-bold text-gray-800 mb-2"</span>&gt;</span>
            Task Management
          <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>
            Organize your tasks efficiently with Prisma &amp; Next.js
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">TaskStats</span> /&gt;</span> {/* show list of tasks */}

        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">AddTaskButton</span> /&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span>
            <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>
              &lt;<span class="hljs-attr">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-center py-12"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 mt-2"</span>&gt;</span>Loading tasks...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            }
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">TaskList</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
  );
}
</code></pre>
<p>If you add a couple of tasks with high priority and mark some of them as completed, you will see a screen with stats as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765874109418/d6c7126d-bf1c-40e3-b32b-9d14b525ee71.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-database-migrations-in-production">Database Migrations in Production</h2>
<p>When you need to change your database schema, Prisma Migrate helps you manage those changes safely.</p>
<h3 id="heading-adding-a-new-field">Adding a New Field</h3>
<p>Let's say you want to add a <code>dueDate</code> field to tasks. First, update your schema from <code>prisma/schema.prisma</code> file:</p>
<pre><code class="lang-bash">model Task {
  id          Int       @id @default(autoincrement())
  title       String
  description String?
  completed   Boolean   @default(<span class="hljs-literal">false</span>)
  priority    String    @default(<span class="hljs-string">"medium"</span>)
  dueDate     DateTime?  // New field
  createdAt   DateTime  @default(now())
  updatedAt   DateTime  @updatedAt
}
</code></pre>
<p>Then create and apply the migration by executing the following command from the terminal:</p>
<pre><code class="lang-bash">npx prisma migrate dev --name add-due-date
</code></pre>
<p>This creates a new migration file and updates your database.</p>
<p>Now, if you navigate to <a target="_blank" href="http://localhost:51212">http://localhost:51212</a>, you will see the new dueDate column added in the Prisma Studio.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765874463836/123cc43f-7a31-4efe-a599-adaef46cdd41.png" alt class="image--center mx-auto" /></p>
<p>If you’re not able to see it, make sure to execute the <code>npx prisma studio</code> command again in a separate terminal and then try it out.</p>
<h3 id="heading-viewing-migration-history">Viewing Migration History</h3>
<p>Check your migration history:</p>
<pre><code class="lang-bash">npx prisma migrate status
</code></pre>
<h3 id="heading-resetting-the-database">Resetting the Database</h3>
<p>During development, you might want to reset your database:</p>
<pre><code class="lang-bash">npx prisma migrate reset
</code></pre>
<blockquote>
<p><strong>Warning:</strong> This deletes all data in your database. Only use this in development!</p>
</blockquote>
<h2 id="heading-best-practices-for-production">Best Practices for Production</h2>
<p>Here are some best practices when using Prisma with Next.js in production:</p>
<h3 id="heading-1-use-environment-variables">1. Use Environment Variables</h3>
<p>Never hardcode database URLs. Always use environment variables in <code>.env</code> file:</p>
<pre><code class="lang-bash">DATABASE_URL=<span class="hljs-string">"file:./prisma/prod.db"</span>
</code></pre>
<h3 id="heading-2-add-a-postinstall-script">2. Add a Postinstall Script</h3>
<p>Add this to your <code>package.json</code> to ensure Prisma Client is generated after installing dependencies:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"postinstall"</span>: <span class="hljs-string">"prisma generate"</span>
  }
}
</code></pre>
<h3 id="heading-3-handle-connection-errors-gracefully">3. Handle Connection Errors Gracefully</h3>
<p>Wrap your database operations in try-catch blocks and provide meaningful error messages to users.</p>
<h3 id="heading-4-use-transactions-for-related-operations">4. Use Transactions for Related Operations</h3>
<p>When you need to perform multiple related database operations, use transactions:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">await</span> prisma.$transaction([
  prisma.task.update({ where: { id: <span class="hljs-number">1</span> }, data: { completed: <span class="hljs-literal">true</span> } }),
  prisma.task.update({ where: { id: <span class="hljs-number">2</span> }, data: { completed: <span class="hljs-literal">true</span> } }),
])
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! You've built a complete Task Management application using Next.js 15 and Prisma 7 with SQLite.</p>
<p><strong>You can find the complete source code for this application in</strong> <a target="_blank" href="https://github.com/myogeshchavan97/prisma-nextjs-task-management-app"><strong>this repository</strong></a><strong>.</strong></p>
<blockquote>
<p>As we cannot cover everything in this tutorial, If you want to learn Next.js from scratch and learn in detail about prisma step-by-step with table relationships, login authentication, multiple routes, server actions and more all while building a large application then, do check out the <a target="_blank" href="https://courses.yogeshchavan.dev/mastering-next-js-15-from-basics-to-advanced">Mastering Next.js course</a>.</p>
</blockquote>
<hr />
<p>In this tutorial, you learned how to:</p>
<ul>
<li><p>Set up Prisma 7 with the new Rust-free architecture</p>
</li>
<li><p>Configure the new <code>prisma.config.ts</code> file</p>
</li>
<li><p>Use driver adapters for database connections</p>
</li>
<li><p>Create and run database migrations</p>
</li>
<li><p>Build Server Actions for CRUD operations</p>
</li>
<li><p>Create a responsive UI with React and Tailwind CSS</p>
</li>
<li><p>Use Prisma Studio for database exploration</p>
</li>
</ul>
<p>Prisma 7's new architecture makes it lighter and more compatible with modern JavaScript runtimes. The driver adapter pattern gives you more flexibility in how you connect to your database.</p>
<h2 id="heading-next-steps">Next Steps</h2>
<p>Here are some ways you can extend this application:</p>
<ul>
<li><p>Add user authentication with NextAuth.js</p>
</li>
<li><p>Implement task categories or tags</p>
</li>
<li><p>Add drag-and-drop for task reordering</p>
</li>
<li><p>Set up due date reminders</p>
</li>
<li><p>Deploy to Vercel or another hosting platform</p>
</li>
<li><p>Migrate to PostgreSQL for a production-ready database</p>
</li>
</ul>
<h2 id="heading-resources">Resources</h2>
<ul>
<li><p><a target="_blank" href="https://www.prisma.io/docs">Prisma Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://www.prisma.io/docs/orm/more/upgrade-guides/upgrading-versions/upgrading-to-prisma-7">Prisma 7 Upgrade Guide</a></p>
</li>
<li><p><a target="_blank" href="https://nextjs.org/docs">Next.js Documentation</a></p>
</li>
</ul>
<hr />
<h2 id="heading-thanks-for-reading">Thanks for reading!</h2>
<p><strong>Access The Ultimate React Ebooks Collection By Clicking The Image Below👇</strong></p>
<p><a target="_blank" href="https://www.dropbox.com/scl/fi/vnszyiunuk62xkspjf09k/12_Redux-Toolkit_Getting_Started.pdf?rlkey=yqrxqjfsqo7wbz8p7vka4ub63&amp;st=s024jf7j&amp;dl=0"><strong>Download The Complete Redux Toolkit Ebook Here</strong></a></p>
<p><a target="_blank" href="https://www.dropbox.com/scl/fi/xdmakhu6sxc2np4wkw8yv/React_Fundamentals_useReducer_Hook.pdf?rlkey=ygyt0febc580j3d3guvyifnpy&amp;st=5zb2mpr2&amp;dl=0"><strong>Download The useReducer Hook Ebook Here</strong></a></p>
<p><a target="_blank" href="https://courses.yogeshchavan.dev/the-ultimate-react-ebooks-components-hooks-redux-routing-and-more"><img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdt00waa0e5sb77xdckwz.png" alt="React Ebooks Collection" /></a></p>
<ul>
<li><p><a target="_blank" href="https://courses.yogeshchavan.dev/"><strong>Check Out All My Courses</strong></a></p>
</li>
<li><p><a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/"><strong>Follow Me On LinkedIn For Regular Updates</strong></a></p>
</li>
<li><p><a target="_blank" href="https://github.com/myogeshchavan97"><strong>GitHub</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[React's/Next.js Worst Week Ever! Just Got Worse]]></title><description><![CDATA[If you're a React/Next.js developer who diligently updated your packages last week after the critical React2Shell vulnerability (CVE-2025-55182), I have some frustrating news: you need to update again.
Security researchers, while probing the patches ...]]></description><link>https://blog.yogeshchavan.dev/reactsnextjs-worst-week-ever-just-got-worse</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/reactsnextjs-worst-week-ever-just-got-worse</guid><category><![CDATA[Next.js]]></category><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Sat, 13 Dec 2025 05:34:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765603952813/bcf3ce7c-1404-495c-8306-3eb884a4b3d2.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you're a React/Next.js developer who diligently updated your packages last week after the critical <a target="_blank" href="https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components">React2Shell vulnerability (CVE-2025-55182)</a>, I have some frustrating news: <strong>you need to update again.</strong></p>
<p>Security researchers, while probing the patches from last week's critical Remote Code Execution fix, discovered two additional vulnerabilities lurking in the same code paths.</p>
<p>The good news? These new vulnerabilities don't allow Remote Code Execution. The bad news? They're still serious enough to warrant immediate action.</p>
<h2 id="heading-whats-new-two-more-cves">What's New: Two More CVEs</h2>
<h3 id="heading-1-denial-of-service-cve-2025-55184-high-severity">1. Denial of Service (CVE-2025-55184) - High Severity</h3>
<p>A malicious HTTP request can trigger an infinite loop when deserialized by React, hanging your server process and consuming CPU. Even if you don't explicitly implement Server Functions, your app may still be vulnerable if it supports React Server Components.</p>
<h3 id="heading-2-source-code-exposure-cve-2025-55183-medium-severity">2. Source Code Exposure (CVE-2025-55183) - Medium Severity</h3>
<p>A crafted request to a vulnerable Server Function can leak its source code, including any hardcoded secrets. If you've got database connection strings, API keys, or credentials directly in your 'use server' functions (instead of environment variables), they could be exposed.</p>
<p>Are You Affected?</p>
<p><strong>You're safe if:</strong></p>
<ul>
<li><p>Your React app is purely client-side (no server)</p>
</li>
<li><p>You don't use a framework/bundler that supports React Server Components</p>
</li>
</ul>
<p><strong>You're vulnerable if you use these packages:</strong></p>
<ul>
<li><p>react-server-dom-webpack</p>
</li>
<li><p>react-server-dom-parcel</p>
</li>
<li><p>react-server-dom-turbopack</p>
</li>
</ul>
<p><strong>Or these frameworks:</strong></p>
<ul>
<li><p>Next.js</p>
</li>
<li><p>React Router</p>
</li>
<li><p>Waku</p>
</li>
<li><p>@parcel/rsc</p>
</li>
<li><p>@vitejs/plugin-rsc</p>
</li>
<li><p>rwsdk (RedwoodJS)</p>
</li>
</ul>
<p><strong>Vulnerable versions:</strong></p>
<p>19.0.0, 19.0.1, 19.0.2, 19.1.0, 19.1.1, 19.1.2, 19.1.2, 19.2.0, 19.2.1 and 19.2.2</p>
<h2 id="heading-step-by-step-fix">Step-by-Step Fix</h2>
<h3 id="heading-nextjs"><strong>Next.js</strong></h3>
<p>All users should upgrade to the latest patched version in their release line:</p>
<pre><code class="lang-bash">npm install next@14.2.35  // <span class="hljs-keyword">for</span> 13.3.x, 13.4.x, 13.5.x, 14.x
npm install next@15.0.7   // <span class="hljs-keyword">for</span> 15.0.x
npm install next@15.1.11  // <span class="hljs-keyword">for</span> 15.1.x
npm install next@15.2.8   // <span class="hljs-keyword">for</span> 15.2.x
npm install next@15.3.8   // <span class="hljs-keyword">for</span> 15.3.x
npm install next@15.4.10  // <span class="hljs-keyword">for</span> 15.4.x
npm install next@15.5.9   // <span class="hljs-keyword">for</span> 15.5.x
npm install next@16.0.10  // <span class="hljs-keyword">for</span> 16.0.x

npm install next@15.6.0-canary.60   // <span class="hljs-keyword">for</span> 15.x canary releases
npm install next@16.1.0-canary.19   // <span class="hljs-keyword">for</span> 16.x canary releases
</code></pre>
<p>If you are on version <code>13.3</code> or later version of Next.js 13 (<code>13.3.x</code>, <code>13.4.x</code>, or <code>13.5.x</code>) please upgrade to version <code>14.2.35</code>.</p>
<p>If you are on <code>next@14.3.0-canary.77</code> or a later Canary release, downgrade to the latest stable 14.x release:</p>
<pre><code class="lang-bash">npm install next@14
</code></pre>
<h3 id="heading-react-router"><strong>React Router</strong></h3>
<p>If you are using React Router’s unstable RSC APIs, you should upgrade the following package.json dependencies if they exist:</p>
<pre><code class="lang-bash">npm install react@latest
npm install react-dom@latest
npm install react-server-dom-parcel@latest
npm install react-server-dom-webpack@latest
npm install @vitejs/plugin-rsc@latest
</code></pre>
<h2 id="heading-key-points-to-remember">Key points to remember:</h2>
<ul>
<li><p>The source code exposure vulnerability can leak secrets <strong>hardcoded in the source code</strong>. Audit any <code>'use server'</code> functions and ensure you're using environment variables (<code>process.env.SECRET</code>) rather than inline secrets, runtime env vars are not exposed.</p>
</li>
<li><p>If you updated last week for the critical RCE vulnerability, you need to update again</p>
</li>
<li><p>Hosting providers like Vercel have temporary mitigations, but don't rely on them</p>
</li>
<li><p>React Native users only need to update if using these specific RSC packages in a monorepo</p>
</li>
</ul>
<hr />
<h2 id="heading-learn-more-about-these-vulnerabilities-in-detail-herehttpsreactdevblog20251211denial-of-service-and-source-code-exposure-in-react-server-components"><a target="_blank" href="https://react.dev/blog/2025/12/11/denial-of-service-and-source-code-exposure-in-react-server-components">Learn more about these vulnerabilities in detail here.</a></h2>
<hr />
<p><strong>Access The Ultimate React Ebooks Collection By Clicking The Image Below👇</strong></p>
<p><a target="_blank" href="https://www.dropbox.com/scl/fi/vnszyiunuk62xkspjf09k/12_Redux-Toolkit_Getting_Started.pdf?rlkey=yqrxqjfsqo7wbz8p7vka4ub63&amp;st=s024jf7j&amp;dl=0"><strong>Download The Complete Redux Toolkit Ebook Here</strong></a></p>
<p><a target="_blank" href="https://www.dropbox.com/scl/fi/xdmakhu6sxc2np4wkw8yv/React_Fundamentals_useReducer_Hook.pdf?rlkey=ygyt0febc580j3d3guvyifnpy&amp;st=5zb2mpr2&amp;dl=0"><strong>Download The useReducer Hook Ebook He</strong></a></p>
<p><a target="_blank" href="https://courses.yogeshchavan.dev/the-ultimate-react-ebooks-components-hooks-redux-routing-and-more"><img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdt00waa0e5sb77xdckwz.png" alt="React Ebooks Collection" /></a></p>
<ul>
<li><p><a target="_blank" href="https://courses.yogeshchavan.dev/"><strong>Check Out All My Courses</strong></a></p>
</li>
<li><p><a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/"><strong>Follow Me On LinkedIn For Regular Updates</strong></a></p>
</li>
<li><p><a target="_blank" href="https://github.com/myogeshchavan97"><strong>GitHub</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[React Performance Anti-Patterns: 5 Mistakes That Kill Your App's Speed!]]></title><description><![CDATA[Is your React app dragging its feet, but you can’t pinpoint the cause?
You might think you’re following the best practices, but some common development patterns are actually degrading your app’s performance behind the scenes.
In this article, we’ll u...]]></description><link>https://blog.yogeshchavan.dev/react-performance-anti-patterns-5-mistakes-that-kill-your-apps-speed</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/react-performance-anti-patterns-5-mistakes-that-kill-your-apps-speed</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Next.js]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Thu, 11 Dec 2025 06:11:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/pBHloi8vrnw/upload/62d094f6872ba18c3cce721b3b10c686.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Is your React app dragging its feet, but you can’t pinpoint the cause?</p>
<p>You might think you’re following the best practices, but some common development patterns are actually degrading your app’s performance behind the scenes.</p>
<p>In this article, we’ll uncover 5 sneaky anti-patterns that are silently killing your React app’s speed, and show you how to fix them for a faster, smoother user experience.</p>
<p>So let’s get started.</p>
<hr />
<h2 id="heading-1-context-causing-mass-re-renders">1. Context Causing Mass Re-renders</h2>
<p><strong>The Problem:</strong> Adding everything in a single context.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765379796364/7727c9ef-dfd8-4c65-b94c-3b5efbbbbff6.png" alt class="image--center mx-auto" /></p>
<p><strong>The Solution:</strong> Split contexts by concern.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765379892275/aab3ae39-a7bb-45fd-a71d-f55b0a6622f6.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-2-inline-objectarray-creation-in-props">2. Inline Object/Array Creation in Props</h2>
<p><strong>The Problem:</strong> Passing inline objects/arrays as props to a component.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765386603113/66772436-f826-4e23-8ee9-64bb5fe2290c.png" alt class="image--center mx-auto" /></p>
<p><strong>First Solution:</strong> Define constants outside the component.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765378662274/773d374d-14fc-47a5-ac66-9b1a390a9de3.png" alt class="image--center mx-auto" /></p>
<p><strong>Second Solution:</strong> Use useMemo for dynamic values.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765378862836/ce99025b-b6ed-44a4-9695-a5ee1ed18dec.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-3-rendering-everything-in-a-huge-list">3. Rendering Everything in a Huge List</h2>
<p><strong>The Problem:</strong> Displaying the entire list at once.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765386710910/4d587526-e914-4641-9b95-d8632302003e.png" alt class="image--center mx-auto" /></p>
<p><strong>The Solution:</strong> Use React Window/React Virtualized library.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765379101894/7ac38d74-408b-4ea8-aa99-641d5c74ea1d.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-4-not-memoizing-expensive-calculations">4. Not Memoizing Expensive Calculations</h2>
<p><strong>The Problem:</strong> Calculating values during rendering.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765379408364/a676ad03-545d-4bac-a335-d06f10541bca.png" alt class="image--center mx-auto" /></p>
<p><strong>The Solution:</strong> Use the useMemo hook.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765379511867/1882f7f8-9102-4fc9-847a-6d9c8665066c.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-5-anonymous-functions-in-jsx">5. Anonymous Functions in JSX</h2>
<p><strong>The Problem:</strong> Creating new functions on every render.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765385903951/548cc750-74c4-4e04-be41-60860488dbf9.png" alt class="image--center mx-auto" /></p>
<p><strong>The Solution:</strong> Use event delegation.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765386007704/c0e31a78-5980-4983-b245-dd9a5077d6a5.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-found-these-tips-useful-download-the-complete-ebook-with-50-such-react-tips-from-the-react-50-pro-tips-ebookhttpscoursesyogeshchavandevreact-50-pro-tips-ebook"><strong>Found these tips useful? Download the complete ebook with 50+ such React tips from the</strong> <a target="_blank" href="https://courses.yogeshchavan.dev/react-50-pro-tips-ebook"><strong>React 50+ Pro Tips Ebook</strong></a><strong>.</strong></h3>
<hr />
<p><strong>Access The Ultimate React Ebooks Collection By Clicking The Image Below👇</strong></p>
<p><a target="_blank" href="https://www.dropbox.com/scl/fi/vnszyiunuk62xkspjf09k/12_Redux-Toolkit_Getting_Started.pdf?rlkey=yqrxqjfsqo7wbz8p7vka4ub63&amp;st=s024jf7j&amp;dl=0"><strong>Download The Complete Redux Toolkit Ebook Here</strong></a></p>
<p><a target="_blank" href="https://www.dropbox.com/scl/fi/xdmakhu6sxc2np4wkw8yv/React_Fundamentals_useReducer_Hook.pdf?rlkey=ygyt0febc580j3d3guvyifnpy&amp;st=5zb2mpr2&amp;dl=0"><strong>Download The useReducer Hook Ebook Here</strong></a></p>
<p><a target="_blank" href="https://courses.yogeshchavan.dev/the-ultimate-react-ebooks-components-hooks-redux-routing-and-more"><img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdt00waa0e5sb77xdckwz.png" alt="React Ebooks Collection" /></a></p>
<ul>
<li><p><a target="_blank" href="https://courses.yogeshchavan.dev/"><strong>Check Out All My Courses</strong></a></p>
</li>
<li><p><a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/"><strong>Follow Me On LinkedIn For Regular Updates</strong></a></p>
</li>
<li><p><a target="_blank" href="https://github.com/myogeshchavan97"><strong>GitHub</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to Access Both Company and Personal GitHub Repositories On The Same Machine]]></title><description><![CDATA[How to Use Separate SSH Keys for Company and Personal GitHub Accounts
Managing multiple GitHub accounts is a common challenge for developers who juggle both personal and professional projects. It becomes even more complex when you want to use differe...]]></description><link>https://blog.yogeshchavan.dev/how-to-access-both-company-and-personal-github-repositories-on-the-same-machine</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/how-to-access-both-company-and-personal-github-repositories-on-the-same-machine</guid><category><![CDATA[GitHub]]></category><category><![CDATA[Git]]></category><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Next.js]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Wed, 10 Dec 2025 10:20:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765361862057/a660e67b-66c7-4ca1-9376-0a79396b1663.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>How to Use Separate SSH Keys for Company and Personal GitHub Accounts</p>
<p>Managing multiple GitHub accounts is a common challenge for developers who juggle both personal and professional projects. It becomes even more complex when you want to use different accounts for AI tools like Lovable AI or Bolt AI to access free credits and keep your repositories synchronized.</p>
<p>Pushing code to the right account without mix-ups requires careful setup. Instead of generating a new SSH key and adding it to your GitHub account every time you switch from a personal project to a company project,</p>
<p>In this article, you will learn how to create separate SSH RSA keys and configure your system to match each key with the appropriate GitHub profile.</p>
<p>By following these steps, you’ll be able to switch seamlessly between accounts and streamline your workflow.</p>
<p>A best practice is to use <strong>separate SSH keys</strong> for each account. This not only improves security but also ensures your commits are correctly attributed and your repositories stay organized.</p>
<hr />
<h2 id="heading-step-1-generate-two-ssh-key-pairs"><strong>Step 1: Generate Two SSH Key Pairs</strong></h2>
<p>Open your terminal and run the following command to create two unique RSA key pairs - one for your company GitHub account and another for your personal GitHub account.</p>
<h3 id="heading-for-your-company-account"><strong>For your company account:</strong></h3>
<pre><code class="lang-bash">ssh-keygen -t rsa -b 4096 -C <span class="hljs-string">"your-company-email@example.com"</span> -f ~/.ssh/id_rsa_company
</code></pre>
<p>For example,</p>
<pre><code class="lang-bash">ssh-keygen -t rsa -b 4096 -C <span class="hljs-string">"mike123@amazon.com"</span> -f ~/.ssh/id_rsa_company
</code></pre>
<ul>
<li><p><code>-C</code> adds a comment (usually your email) to identify the key.</p>
</li>
<li><p><code>-f</code> specifies the filename to avoid overwriting default keys.</p>
</li>
</ul>
<p>You’ll be prompted to set a <strong>password</strong> - highly recommended for added security.</p>
<p>This creates two different files: <code>~/.ssh/id_rsa_company</code> and <code>~/.ssh/id_rsa_company.pub</code></p>
<h3 id="heading-for-your-personal-account"><strong>For your personal account:</strong></h3>
<pre><code class="lang-bash">ssh-keygen -t rsa -b 4096 -C <span class="hljs-string">"your-personal-email@example.com"</span> -f ~/.ssh/id_rsa_personal
</code></pre>
<p>For example,</p>
<pre><code class="lang-bash">ssh-keygen -t rsa -b 4096 -C <span class="hljs-string">"mike123@gmail.com"</span> -f ~/.ssh/id_rsa_personal
</code></pre>
<p>This creates two different files: <code>~/.ssh/id_rsa_personal</code> and <code>~/.ssh/id_rsa_personal.pub</code></p>
<h2 id="heading-step-2-configure-ssh-to-use-the-right-key"><strong>Step 2: Configure SSH to Use The Right Key</strong></h2>
<p>Create or edit the SSH config file to tell your system which key to use for which GitHub account.</p>
<p>Execute the following command from your terminal/command prompt:</p>
<pre><code class="lang-bash">vi ~/.ssh/config
</code></pre>
<p>and add the following configuration inside that file:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Company GitHub Account</span>
Host github-company
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_rsa_company
  IdentitiesOnly yes

<span class="hljs-comment"># Personal GitHub Account</span>
Host github-personal
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_rsa_personal
  IdentitiesOnly yes
</code></pre>
<p>Save the file and close it.</p>
<blockquote>
<p>You can create as many SSH keys as you want depending on the number of GitHub accounts you want to manage.</p>
</blockquote>
<h2 id="heading-step-3-add-public-keys-to-your-github-account"><strong>Step 3: Add Public Keys to Your GitHub Account</strong></h2>
<p>Execute the following command to see the generated public key for your company's GitHub account:</p>
<pre><code class="lang-javascript">cat ~<span class="hljs-regexp">/.ssh/i</span>d_rsa_company.pub
</code></pre>
<p>You will see output something like this:</p>
<pre><code class="lang-bash">ssh-rsa AAAAB3kXU3onx6Qp8J5LL0noFecbBPyGiTPk6KarqLGKl5MIZ2KDMA+UFMEQ== mike123@amazon.com
</code></pre>
<p>Now copy the complete text starting from <code>ssh-rsa</code> and ending with your email <code>mike123@amazon.com</code>.</p>
<blockquote>
<p>Make sure to not select any extra space or extra character while copying the text.</p>
</blockquote>
<h3 id="heading-adding-copied-key-to-company-github-account"><strong>Adding Copied Key To Company GitHub Account:</strong></h3>
<p>Now open your company GitHub account and navigate to <a target="_blank" href="https://github.com/settings/profile">https://github.com/settings/profile</a>. You will see the following navigation menus:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765344864106/800785bb-9f86-485c-a982-5d3cbfff75bb.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Now, click on the <code>SSH and GPG keys</code> submenu under <code>Access</code> menu.</p>
</li>
<li><p>Click on the <code>New SSH Key</code> button displayed on the top right corner. You will see the following screen.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765345072024/24ba5818-441d-4688-bec5-5de8b0ff491f.png" alt="Add SSH Key" class="image--center mx-auto" /></p>
<ul>
<li>Give any title you want and paste the copied key in the <code>Key</code> textarea, and click on the <code>Add SSH key</code> button.</li>
</ul>
<p>Similarly, you can execute the following command to see the generated public key for your personal GitHub account:</p>
<pre><code class="lang-javascript">cat ~<span class="hljs-regexp">/.ssh/i</span>d_rsa_personal.pub
</code></pre>
<p>Now copy the complete text starting from <code>ssh-rsa</code> and ending with your email <code>mike123@gmail.com</code>.</p>
<p>Now log in to your personal GitHub account and follow the same steps above of <code>Adding Copied Key To Company GitHub Account</code> to add this key to your GitHub account.</p>
<p>Congratulations! With this, we’re done with the setup.</p>
<hr />
<p>Let's try to clone a repository to see if it works.</p>
<p>Go to any of your own GitHub repositories from your personal GitHub account and copy the SSH key from <code>SSH</code> tab by clicking on the green <code>Code</code> button as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765345670308/e74cd189-3940-40e2-9d3b-5cd177dbae6d.png" alt="Clone Repository" class="image--center mx-auto" /></p>
<p>Now, open your terminal and execute the following command to clone the repository:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> your_copied_url
</code></pre>
<p>For example,</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> git@github.com:myogeshchavan97/unsplash_image_search.git
</code></pre>
<p>Note that, in the above copied URL, you need to replace <code>git@github.com</code> with <code>git@github-personal</code> keeping everything else as it is. If you want to clone your personal GitHub repository like this:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> git@github-personal:myogeshchavan97/unsplash_image_search.git
</code></pre>
<p>If you want to clone your company's GitHub repository code, you need to use <code>git@github-company</code> like this:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> git@github-company:myogeshchavan97/unsplash_image_search.git
</code></pre>
<p>This is because, if you remember, in step 2 above <code>Step 2: Configure SSH to Use The Right Key</code>, we have named it <code>github-company</code> as the <code>Host</code> inside the <code>~/.ssh/config</code> file for the <code>Company GitHub Account</code> and <code>github-personal</code> as the <code>Host</code> for <code>Personal GitHub Account</code>.</p>
<p>Similarly, if you want to connect your local GitHub repository on your machine to your personal GitHub account, you need to execute the following command from the terminal:</p>
<pre><code class="lang-bash">git remote add origin your_remote_git_url
</code></pre>
<p>For example,</p>
<pre><code class="lang-bash">git remote add origin git@github-personal:myogeshchavan97/test_repo.git
</code></pre>
<p>Note that here, we have used <code>git@github-personal</code> instead of <code>git@github.com</code>.</p>
<p>Similarly, if you want to connect your local GitHub repository to your company's GitHub account, you need to execute the following command from the terminal:</p>
<pre><code class="lang-bash">git remote add origin git@github-company:myogeshchavan97/test_repo.git
</code></pre>
<p>Note that here, we have replaced <code>git@github.com</code> with <code>git@github-company</code>.</p>
<p>That’s it! You now have isolated SSH keys for company and personal GitHub accounts.</p>
<p><strong>Access The Ultimate React Ebooks Collection By Clicking The Image Below👇</strong></p>
<p><a target="_blank" href="https://www.dropbox.com/scl/fi/vnszyiunuk62xkspjf09k/12_Redux-Toolkit_Getting_Started.pdf?rlkey=yqrxqjfsqo7wbz8p7vka4ub63&amp;st=s024jf7j&amp;dl=0">Download The Complete Redux Toolkit Ebook Here</a></p>
<p><a target="_blank" href="https://www.dropbox.com/scl/fi/xdmakhu6sxc2np4wkw8yv/React_Fundamentals_useReducer_Hook.pdf?rlkey=ygyt0febc580j3d3guvyifnpy&amp;st=5zb2mpr2&amp;dl=0">Download The useReducer Hook Ebook He</a></p>
<p><a target="_blank" href="https://courses.yogeshchavan.dev/the-ultimate-react-ebooks-components-hooks-redux-routing-and-more"><img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdt00waa0e5sb77xdckwz.png" alt="React Ebooks Collection" /></a></p>
<ul>
<li><p><a target="_blank" href="https://courses.yogeshchavan.dev/"><strong>Check Out All My Courses</strong></a></p>
</li>
<li><p><a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/"><strong>Follow Me On LinkedIn For Regular Updates</strong></a></p>
</li>
<li><p><a target="_blank" href="https://github.com/myogeshchavan97"><strong>GitHub</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to Build Multi-Language React Apps with Internationalization (i18n)]]></title><description><![CDATA[Have you ever built a React app only to realize that users from different countries can't use it effectively because it only supports English?
In this tutorial, you'll learn how to build truly global React application using internationalization (i18n...]]></description><link>https://blog.yogeshchavan.dev/how-to-build-multi-language-react-apps-with-internationalization-i18n</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/how-to-build-multi-language-react-apps-with-internationalization-i18n</guid><category><![CDATA[React]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Mon, 08 Dec 2025 07:09:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765177713051/fc234e26-50a3-4528-9afb-5bc239ce280c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever built a React app only to realize that users from different countries can't use it effectively because it only supports English?</p>
<p>In this tutorial, you'll learn how to build truly global React application using internationalization (i18n). You'll discover how to manage translations, handle date and number formatting for different locales, and implement language switching – all while maintaining a clean, scalable codebase.</p>
<h2 id="heading-what-is-internationalization-i18n">What is Internationalization (i18n)?</h2>
<p>Internationalization (i18n) is the process of designing and developing your application so it can be easily adapted to different languages and regions without requiring engineering changes.</p>
<p>The term "i18n" comes from the fact that there are 18 letters between the first "i" and the last "n" in "internationalization".</p>
<p>Key aspects of i18n include:</p>
<ul>
<li><p><strong>Translation</strong>: Converting text strings to different languages</p>
</li>
<li><p><strong>Localization</strong>: Adapting content for specific regions (dates, numbers, currencies)</p>
</li>
<li><p><strong>Pluralization</strong>: Handling singular/plural forms correctly in each language</p>
</li>
</ul>
<h2 id="heading-why-i18n-matters-for-your-react-app">Why i18n Matters for Your React App</h2>
<p>Here are several compelling reasons why you should internationalize your React application:</p>
<ol>
<li><p><strong>Global Reach</strong>: Reach users in their native language and expand to new markets</p>
</li>
<li><p><strong>Better User Experience</strong>: Users prefer apps in their own language – studies show 75% of users prefer buying products in their native language</p>
</li>
<li><p><strong>Competitive Advantage</strong>: Many apps lack proper internationalization, giving you an edge</p>
</li>
<li><p><strong>Legal Requirements</strong>: Some countries require apps to be available in local languages</p>
</li>
<li><p><strong>SEO Benefits</strong>: Multi-language content improves search rankings in different regions</p>
</li>
<li><p><strong>Increased Conversions</strong>: Users are more likely to complete actions when content is in their language</p>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this tutorial, you should have:</p>
<ul>
<li><p>Basic knowledge of React and React Hooks</p>
</li>
<li><p>Node.js and npm installed on your machine</p>
</li>
<li><p>A code editor like VS Code</p>
</li>
</ul>
<h2 id="heading-project-setup">Project Setup</h2>
<p>Let's create a new React application using Vite:</p>
<pre><code class="lang-javascript">npm create vite@latest react-i18n-demo -- --template react
cd react-i18n-demo
</code></pre>
<p>Next, install the required i18n packages:</p>
<pre><code class="lang-javascript">npm install i18next react-i18next i18next-browser-languagedetector
</code></pre>
<p>Here's what each package does:</p>
<ul>
<li><p><strong>i18next</strong>: Core internationalization framework</p>
</li>
<li><p><strong>react-i18next</strong>: React bindings for i18next</p>
</li>
<li><p><strong>i18next-browser-languagedetector</strong>: Automatically detects user's preferred language</p>
</li>
</ul>
<p>Now start the development server:</p>
<pre><code class="lang-javascript">npm run dev
</code></pre>
<p>Your app should now be running on <a target="_blank" href="http://localhost:5173/">http://localhost:5173/</a></p>
<p>Note that, in this tutorial we will not be using any styling library or framework like Tailwind CSS.</p>
<p>For simplicity, we will be defining styles inline however, in your real application, you should never define styles inline. Always separate out into their own CSS files or use CSS framework like Tailwind CSS.</p>
<p>So delete the <code>src/App.css</code> file and replace the content of <code>src/index.css</code> with the following content:</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">font-family</span>: system-ui, Avenir, Helvetica, Arial, sans-serif;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.5</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">400</span>;
}
</code></pre>
<h2 id="heading-the-problem-hardcoded-strings">The Problem: Hardcoded Strings</h2>
<p>Before we implement i18n, let's look at a typical React component with hardcoded strings:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductCard</span>(<span class="hljs-params">{ product }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
      <span class="hljs-attr">padding:</span> '<span class="hljs-attr">20px</span>',
      <span class="hljs-attr">border:</span> '<span class="hljs-attr">1px</span> <span class="hljs-attr">solid</span> #<span class="hljs-attr">ddd</span>',
      <span class="hljs-attr">borderRadius:</span> '<span class="hljs-attr">8px</span>'
    }}&gt;</span>
      {/* ❌ Hardcoded English strings */}
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Price: ${product.price}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>In stock: {product.stock} items<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

      {product.stock === 0 &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> '<span class="hljs-attr">red</span>' }}&gt;</span>Out of stock<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}

      {product.stock === 1 &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> '<span class="hljs-attr">orange</span>' }}&gt;</span>Only 1 item left!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}

      {product.stock &gt; 1 &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> '<span class="hljs-attr">green</span>' }}&gt;</span>In stock<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>Add to cart<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ProductCard;
</code></pre>
<p>This approach has several problems:</p>
<ol>
<li><p><strong>No Translation Support</strong>: All text is in English only</p>
</li>
<li><p><strong>Maintenance Nightmare</strong>: Changing text requires editing multiple components</p>
</li>
<li><p><strong>No Pluralization</strong>: Handling "1 item" vs "2 items" is hardcoded</p>
</li>
<li><p><strong>No Localization</strong>: Date and number formats are fixed</p>
</li>
<li><p><strong>Difficult Scaling</strong>: Adding new languages requires modifying every component</p>
</li>
</ol>
<p>Let's fix these issues with proper internationalization.</p>
<h2 id="heading-the-solution-react-i18next">The Solution: react-i18next</h2>
<p>The most popular and powerful solution for React internationalization is <strong>react-i18next</strong>.</p>
<p>It provides:</p>
<ul>
<li><p>Simple API for translations</p>
</li>
<li><p>Automatic language detection</p>
</li>
<li><p>Pluralization support</p>
</li>
<li><p>Nested translations</p>
</li>
<li><p>Formatting for dates, numbers, and currencies</p>
</li>
<li><p>Lazy loading of translation files</p>
</li>
<li><p>TypeScript support</p>
</li>
</ul>
<h2 id="heading-how-to-create-translation-files">How to Create Translation Files</h2>
<p>For larger applications, it's better to organize translations in separate JavaScript files.</p>
<p>So, create a new <code>utils</code> folder inside <code>src</code> folder and inside it create <code>locales</code> folder where translations will be stored like this:</p>
<pre><code class="lang-javascript">utils/
  locales/
    en/
      translation.js
    es/
      translation.js
    fr/
      translation.js
</code></pre>
<p>Here's an example <code>utils/locales/en/translation.js</code> file for english translations with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">en</span>: {
    <span class="hljs-attr">translation</span>: {
      <span class="hljs-string">"product.price"</span>: <span class="hljs-string">"Price"</span>,
      <span class="hljs-string">"product.inStock"</span>: <span class="hljs-string">"In stock: {{count}} items"</span>,
      <span class="hljs-string">"product.outOfStock"</span>: <span class="hljs-string">"Out of stock"</span>,
      <span class="hljs-string">"product.onlyOneLeft"</span>: <span class="hljs-string">"Only 1 item left!"</span>,
      <span class="hljs-string">"product.addToCart"</span>: <span class="hljs-string">"Add to cart"</span>,

      <span class="hljs-string">"profile.welcome"</span>: <span class="hljs-string">"Welcome, {{name}}!"</span>,
      <span class="hljs-string">"profile.memberSince"</span>: <span class="hljs-string">"Member since: {{date}}"</span>,
      <span class="hljs-string">"profile.loyaltyPoints"</span>: <span class="hljs-string">"You have {{points}} loyalty points"</span>,
      <span class="hljs-string">"profile.orders_zero"</span>: <span class="hljs-string">"You have no orders"</span>,
      <span class="hljs-string">"profile.orders_one"</span>: <span class="hljs-string">"You have 1 order"</span>,
      <span class="hljs-string">"profile.orders_other"</span>: <span class="hljs-string">"You have {{count}} orders"</span>,
      <span class="hljs-string">"profile.editProfile"</span>: <span class="hljs-string">"Edit profile"</span>,
    },
  },
};
</code></pre>
<p>Similarly, create <code>utils/locales/es/translation.js</code> file for spanish translations with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">es</span>: {
    <span class="hljs-attr">translation</span>: {
      <span class="hljs-string">"product.price"</span>: <span class="hljs-string">"Precio"</span>,
      <span class="hljs-string">"product.inStock"</span>: <span class="hljs-string">"En stock: {{count}} artículos"</span>,
      <span class="hljs-string">"product.outOfStock"</span>: <span class="hljs-string">"Agotado"</span>,
      <span class="hljs-string">"product.onlyOneLeft"</span>: <span class="hljs-string">"¡Solo queda 1 artículo!"</span>,
      <span class="hljs-string">"product.addToCart"</span>: <span class="hljs-string">"Añadir al carrito"</span>,

      <span class="hljs-string">"profile.welcome"</span>: <span class="hljs-string">"¡Bienvenido, {{name}}!"</span>,
      <span class="hljs-string">"profile.memberSince"</span>: <span class="hljs-string">"Miembro desde: {{date}}"</span>,
      <span class="hljs-string">"profile.loyaltyPoints"</span>: <span class="hljs-string">"Tienes {{points}} puntos de fidelidad"</span>,
      <span class="hljs-string">"profile.orders_zero"</span>: <span class="hljs-string">"No tienes pedidos"</span>,
      <span class="hljs-string">"profile.orders_one"</span>: <span class="hljs-string">"Tienes 1 pedido"</span>,
      <span class="hljs-string">"profile.orders_other"</span>: <span class="hljs-string">"Tienes {{count}} pedidos"</span>,
      <span class="hljs-string">"profile.editProfile"</span>: <span class="hljs-string">"Editar perfil"</span>,
    },
  },
};
</code></pre>
<p>Similarly, create <code>utils/locales/fr/translation.js</code> file for french translations with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">fr</span>: {
    <span class="hljs-attr">translation</span>: {
      <span class="hljs-string">"product.price"</span>: <span class="hljs-string">"Prix"</span>,
      <span class="hljs-string">"product.inStock"</span>: <span class="hljs-string">"En stock: {{count}} articles"</span>,
      <span class="hljs-string">"product.outOfStock"</span>: <span class="hljs-string">"Rupture de stock"</span>,
      <span class="hljs-string">"product.onlyOneLeft"</span>: <span class="hljs-string">"Plus qu'un article !"</span>,
      <span class="hljs-string">"product.addToCart"</span>: <span class="hljs-string">"Ajouter au panier"</span>,

      <span class="hljs-string">"profile.welcome"</span>: <span class="hljs-string">"Bienvenue, {{name}} !"</span>,
      <span class="hljs-string">"profile.memberSince"</span>: <span class="hljs-string">"Membre depuis : {{date}}"</span>,
      <span class="hljs-string">"profile.loyaltyPoints"</span>: <span class="hljs-string">"Vous avez {{points}} points de fidélité"</span>,
      <span class="hljs-string">"profile.orders_zero"</span>: <span class="hljs-string">"Vous n'avez aucune commande"</span>,
      <span class="hljs-string">"profile.orders_one"</span>: <span class="hljs-string">"Vous avez 1 commande"</span>,
      <span class="hljs-string">"profile.orders_other"</span>: <span class="hljs-string">"Vous avez {{count}} commandes"</span>,
      <span class="hljs-string">"profile.editProfile"</span>: <span class="hljs-string">"Modifier le profil"</span>,
    },
  },
};
</code></pre>
<h2 id="heading-how-to-set-up-react-i18next">How to Set Up react-i18next</h2>
<p>Now, create a <code>i18n.js</code> file inside <code>utils</code> folder and add the following contents inside it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> i18n <span class="hljs-keyword">from</span> <span class="hljs-string">"i18next"</span>;
<span class="hljs-keyword">import</span> LanguageDetector <span class="hljs-keyword">from</span> <span class="hljs-string">"i18next-browser-languagedetector"</span>;
<span class="hljs-keyword">import</span> { initReactI18next } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-i18next"</span>;
<span class="hljs-keyword">import</span> enTranslations <span class="hljs-keyword">from</span> <span class="hljs-string">"./locales/en/translation"</span>;
<span class="hljs-keyword">import</span> esTranslations <span class="hljs-keyword">from</span> <span class="hljs-string">"./locales/es/translation"</span>;
<span class="hljs-keyword">import</span> frTranslations <span class="hljs-keyword">from</span> <span class="hljs-string">"./locales/fr/translation"</span>;

<span class="hljs-keyword">const</span> resources = {
  <span class="hljs-comment">// English translations</span>
  ...enTranslations,
  <span class="hljs-comment">// Spanish translations</span>
  ...esTranslations,
  <span class="hljs-comment">// French translations</span>
  ...frTranslations,
};

<span class="hljs-comment">// Initialize i18next</span>
i18n
  .use(LanguageDetector) <span class="hljs-comment">// Detect user language</span>
  .use(initReactI18next) <span class="hljs-comment">// Pass to react-i18next</span>
  .init({
    resources,
    <span class="hljs-attr">fallbackLng</span>: <span class="hljs-string">"en"</span>, <span class="hljs-comment">// Default language if detection fails</span>

    <span class="hljs-attr">interpolation</span>: {
      <span class="hljs-attr">escapeValue</span>: <span class="hljs-literal">false</span>,

      <span class="hljs-comment">// Custom formatter for dates and currencies</span>
      <span class="hljs-attr">format</span>: <span class="hljs-function">(<span class="hljs-params">value, format, lng</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (format === <span class="hljs-string">"currency"</span>) {
          <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Intl</span>.NumberFormat(lng, {
            <span class="hljs-attr">style</span>: <span class="hljs-string">"currency"</span>,
            <span class="hljs-attr">currency</span>: lng === <span class="hljs-string">"en"</span> ? <span class="hljs-string">"USD"</span> : lng === <span class="hljs-string">"es"</span> ? <span class="hljs-string">"EUR"</span> : <span class="hljs-string">"EUR"</span>,
          }).format(value);
        }

        <span class="hljs-keyword">if</span> (format === <span class="hljs-string">"date"</span>) {
          <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Intl</span>.DateTimeFormat(lng, {
            <span class="hljs-attr">year</span>: <span class="hljs-string">"numeric"</span>,
            <span class="hljs-attr">month</span>: <span class="hljs-string">"long"</span>,
            <span class="hljs-attr">day</span>: <span class="hljs-string">"numeric"</span>,
          }).format(value);
        }

        <span class="hljs-keyword">return</span> value;
      },
    },
  });

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> i18n;
</code></pre>
<p>Here, we have imported all the translations files and added inside the <code>resources</code> object and passed it to <code>init</code> function of <code>i18n</code>.</p>
<p>Also, note that we’re using <code>i18next-browser-languagedetector</code> package which gives us <code>LanguageDetector</code> which we’re passing to <code>use</code> function so it automatically detects language of the user who’s browsing the application.</p>
<p>It’s important to know that we’re passing an object with <code>resources</code> property to <code>init</code> function. It has to be called <code>resources</code> as it’s predefined property which init function expects.</p>
<p>Now import this configuration in your <code>src/main.jsx</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { StrictMode } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App.jsx"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./utils/i18n"</span>;

createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>)).render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">StrictMode</span>&gt;</span></span>
);
</code></pre>
<h2 id="heading-understanding-translation-variables-and-interpolation">Understanding Translation Variables and Interpolation</h2>
<p>Before diving into using translations in components, it's crucial to understand how variables and interpolation work in i18next. This will make it much easier to create dynamic, reusable translations.</p>
<h3 id="heading-what-is-interpolation">What is Interpolation?</h3>
<p>Interpolation is the process of inserting dynamic values into translation strings. Instead of having separate translations for every possible variation, you can use placeholders that get replaced with actual values at runtime.</p>
<p>For example, instead of creating separate translations like:</p>
<ul>
<li><p>"Welcome, John!"</p>
</li>
<li><p>"Welcome, Sarah!"</p>
</li>
<li><p>"Welcome, Michael!"</p>
</li>
</ul>
<p>You create one translation with a placeholder:</p>
<ul>
<li>"Welcome, {{name}}!"</li>
</ul>
<h3 id="heading-basic-variable-interpolation">Basic Variable Interpolation</h3>
<p>The most basic form of interpolation uses double curly braces <code>{{variableName}}</code> as placeholders:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// import useTranslation hook</span>
<span class="hljs-keyword">import</span> { useTranslation } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-i18next'</span>;

<span class="hljs-comment">// use it inside component </span>
<span class="hljs-keyword">const</span> { t } = useTranslation();

<span class="hljs-comment">// Translation string</span>
<span class="hljs-string">"Welcome"</span>: <span class="hljs-string">"Welcome, {{name}}!"</span>

<span class="hljs-comment">// Usage in code</span>
t(<span class="hljs-string">'Welcome'</span>, { <span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span> })
<span class="hljs-comment">// Output: "Welcome, John!"</span>

<span class="hljs-comment">// Translation string</span>
<span class="hljs-string">"product.inStock"</span>: <span class="hljs-string">"In stock: {{count}} items"</span>

<span class="hljs-comment">// Usage in code</span>
t(<span class="hljs-string">'product.inStock'</span>, { <span class="hljs-attr">count</span>: <span class="hljs-number">10</span> })
<span class="hljs-comment">// Output: "In stock: 10 items"</span>
</code></pre>
<p>When you call the <code>t</code> function, you pass an object as the second argument containing the values you want to interpolate.</p>
<h2 id="heading-how-to-use-translations-in-components">How to Use Translations in Components</h2>
<p>Now let's update our code to use translations instead of hardcoded strings.</p>
<h3 id="heading-using-the-usetranslation-hook">Using the useTranslation Hook</h3>
<p>The <code>useTranslation</code> hook is the primary way to access translations in functional components.</p>
<p>So, create a <code>components</code>folder inside <code>src</code> folder and create <code>ProductCard.jsx</code> file inside it and add the following contents inside it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useTranslation } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-i18next"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductCard</span>(<span class="hljs-params">{ product }</span>) </span>{
  <span class="hljs-keyword">const</span> { t } = useTranslation();
  <span class="hljs-keyword">const</span> zeroLeft = product.stock === <span class="hljs-number">0</span>;
  <span class="hljs-keyword">const</span> oneLeft = product.stock === <span class="hljs-number">1</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        {t("product.price")}: ${product.price}
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{t("product.inStock", { count: product.stock })}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

      {zeroLeft &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> "<span class="hljs-attr">red</span>" }}&gt;</span>{t("product.outOfStock")}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}

      {oneLeft &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> "<span class="hljs-attr">orange</span>" }}&gt;</span>{t("product.onlyOneLeft")}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      )}

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">disabled</span>=<span class="hljs-string">{zeroLeft}</span>&gt;</span>{t("product.addToCart")}<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ProductCard;
</code></pre>
<p>As you can see in the above code, we’re using the properties from the <code>translation.js</code> file while calling the <code>t</code> function to get specific translation text.</p>
<p>Now, let’s use this component and display it on the UI.</p>
<p>Open <code>src/App.jsx</code> file and replace it with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> ProductCard <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/ProductCard"</span>;

<span class="hljs-keyword">const</span> product = {
  <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Laptop"</span>,
  <span class="hljs-attr">price</span>: <span class="hljs-number">999</span>,
  <span class="hljs-attr">stock</span>: <span class="hljs-number">5</span>,
};

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ProductCard</span> <span class="hljs-attr">product</span>=<span class="hljs-string">{product}</span> /&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now, If you check the application, you will see the following output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764872286258/b7a6edc3-484b-4b4d-bbd7-d4ce433edcdc.png" alt class="image--center mx-auto" /></p>
<p>As you can see, we correctly see the translation and interpolated values from the <code>translation.js</code> file.</p>
<h3 id="heading-multiple-variables-in-one-string">Multiple Variables in One String</h3>
<p>You can use multiple variables in a single translation string:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Translation string</span>
<span class="hljs-string">"greeting"</span>: <span class="hljs-string">"Hello {{firstName}} {{lastName}}, you have {{count}} new messages."</span>

<span class="hljs-comment">// Usage in code</span>
t(<span class="hljs-string">'greeting'</span>, { 
  <span class="hljs-attr">firstName</span>: <span class="hljs-string">'John'</span>, 
  <span class="hljs-attr">lastName</span>: <span class="hljs-string">'Doe'</span>, 
  <span class="hljs-attr">count</span>: <span class="hljs-number">5</span> 
})
<span class="hljs-comment">// Output: "Hello John Doe, you have 5 new messages."</span>
</code></pre>
<h3 id="heading-interpolation-with-counts-pluralization">Interpolation with Counts (Pluralization)</h3>
<p>One of the most powerful features is combining interpolation with pluralization. i18next automatically handles plural forms based on the count:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-string">"items_zero"</span>: <span class="hljs-string">"You have no items"</span>,
  <span class="hljs-string">"items_one"</span>: <span class="hljs-string">"You have {{count}} item"</span>,
  <span class="hljs-string">"items_other"</span>: <span class="hljs-string">"You have {{count}} items"</span>
}
</code></pre>
<p>When you use the <code>count</code> parameter, i18next automatically selects the correct plural form:</p>
<pre><code class="lang-javascript">t(<span class="hljs-string">'items'</span>, { <span class="hljs-attr">count</span>: <span class="hljs-number">0</span> })  <span class="hljs-comment">// "You have no items"</span>
t(<span class="hljs-string">'items'</span>, { <span class="hljs-attr">count</span>: <span class="hljs-number">1</span> })  <span class="hljs-comment">// "You have 1 item"</span>
t(<span class="hljs-string">'items'</span>, { <span class="hljs-attr">count</span>: <span class="hljs-number">5</span> })  <span class="hljs-comment">// "You have 5 items"</span>
</code></pre>
<p>Different languages have different pluralization rules. For example:</p>
<ul>
<li><p><strong>English</strong>: zero, one, other</p>
</li>
<li><p><strong>Polish</strong>: zero, one, few, many, other</p>
</li>
<li><p><strong>Arabic</strong>: zero, one, two, few, many, other</p>
</li>
</ul>
<p>i18next handles these differences automatically!</p>
<h3 id="heading-custom-formatting-with-interpolation">Custom Formatting with Interpolation</h3>
<p>You can also apply formatting to interpolated values. This is particularly useful for dates, currencies, and numbers:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"price"</span>: <span class="hljs-string">"Price: {{amount, currency}}"</span>
<span class="hljs-string">"lastLogin"</span>: <span class="hljs-string">"Last login: {{date, date}}"</span>
</code></pre>
<p><strong>Usage:</strong></p>
<pre><code class="lang-javascript">t(<span class="hljs-string">'price'</span>, { <span class="hljs-attr">amount</span>: <span class="hljs-number">99.99</span> })
<span class="hljs-comment">// Output with formatting: "Price: $99.99" (in English)</span>
<span class="hljs-comment">// Output with formatting: "Price: 99,99 €" (in French)</span>

t(<span class="hljs-string">'lastLogin'</span>, { <span class="hljs-attr">date</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>() })
<span class="hljs-comment">// Output: "Last login: December 4, 2024" (in English)</span>
<span class="hljs-comment">// Output: "Last login: 4 décembre 2024" (in French)</span>
</code></pre>
<p>If you remember, we added a <code>format</code> function inside the <code>utils/i18n.js</code> file because of which we see the $ in <code>$99.99</code> and <code>€</code> in <code>99,99 €</code> if the user’s language is french <code>fr</code>.</p>
<p>If you want to see that in action, open <code>src/main.jsx</code> file and add the following import at the top of the file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> i18next <span class="hljs-keyword">from</span> <span class="hljs-string">"i18next"</span>;
</code></pre>
<p>and call the <code>changeLanguage</code> method from <code>i18next</code> by passing <code>fr</code> as the value.</p>
<p>Here’s the complete code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> i18next <span class="hljs-keyword">from</span> <span class="hljs-string">"i18next"</span>; <span class="hljs-comment">// import i18next package</span>
<span class="hljs-keyword">import</span> { StrictMode } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom/client"</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">"./App.jsx"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./index.css"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./utils/i18n"</span>;

i18next.changeLanguage(<span class="hljs-string">"fr"</span>); <span class="hljs-comment">// change language to french</span>

createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>)).render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">StrictMode</span>&gt;</span></span>
);
</code></pre>
<p>And as a temporary code you can add the following JSX inside the <code>ProductCard.jsx</code> file:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
     {/*  your old JSX */}

      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{t("price", { amount: 99.99 })}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{t("lastLogin", { date: new Date() })}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

      {/*  your new JSX */}
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
);
</code></pre>
<p>Now, If you check the application, you will the following output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764928731678/43a91e4a-2523-4bdb-91f4-95407aff9474.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-important-notes-about-interpolation">Important Notes About Interpolation</h3>
<ol>
<li><p><strong>Escaping</strong>: By default, i18next doesn't escape HTML in interpolated values because React already handles escaping. This is why we set <code>escapeValue: false</code> in the <code>utils/i18n.js</code> file.</p>
</li>
<li><p><strong>Missing Variables</strong>: If you forget to pass a required variable, i18next will leave the placeholder as it is in the output so never forget to pass the value for placeholder</p>
</li>
</ol>
<pre><code class="lang-javascript">t(<span class="hljs-string">'welcome'</span>, {})  <span class="hljs-comment">// Output: "Welcome, {{name}}!"</span>
</code></pre>
<ol start="3">
<li><strong>Default Values</strong>: You can provide fallback values:</li>
</ol>
<pre><code class="lang-javascript">t(<span class="hljs-string">'welcome'</span>, { <span class="hljs-attr">name</span>: userName || <span class="hljs-string">'Guest'</span> })
</code></pre>
<ol start="4">
<li><strong>Performance</strong>: Interpolation is very fast, so don't worry about using it extensively in your app.</li>
</ol>
<p>Now that you understand how variables and interpolation work, you're ready to use them effectively in your components!</p>
<p>Now, create a <code>UserProfile.jsx</code> file inside the <code>components</code>folder and add the following contents inside it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useTranslation } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-i18next"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserProfile</span>(<span class="hljs-params">{ user }</span>) </span>{
  <span class="hljs-keyword">const</span> { t } = useTranslation();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{t("profile.welcome", { name: user.name })}<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{t("profile.loyaltyPoints", { points: user.points })}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> UserProfile;
</code></pre>
<p>Now, let’s use this component inside the <code>App.jsx</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> ProductCard <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/ProductCard"</span>;
<span class="hljs-keyword">import</span> UserProfile <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/UserProfile"</span>;

<span class="hljs-keyword">const</span> product = {
  <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Laptop"</span>,
  <span class="hljs-attr">price</span>: <span class="hljs-number">999</span>,
  <span class="hljs-attr">stock</span>: <span class="hljs-number">5</span>,
};

<span class="hljs-keyword">const</span> user = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">"John"</span>,
  <span class="hljs-attr">points</span>: <span class="hljs-number">150</span>,
};

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ProductCard</span> <span class="hljs-attr">product</span>=<span class="hljs-string">{product}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">UserProfile</span> <span class="hljs-attr">user</span>=<span class="hljs-string">{user}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>If you check the application now, you will see the following output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764923219041/e2dff366-9d3e-4639-9c5e-6dfde5874d24.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-how-to-build-a-language-switcher">How to Build a Language Switcher</h2>
<p>A language switcher allows users to change the application language. Here's how to build one.</p>
<p>Inside <code>components</code> folder create a new file with name <code>LanguageSwitcher.jsx</code> and add the following content inside it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useTranslation } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-i18next"</span>;

<span class="hljs-keyword">const</span> languages = [
  { <span class="hljs-attr">code</span>: <span class="hljs-string">"en"</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">"English"</span>, <span class="hljs-attr">flag</span>: <span class="hljs-string">"🇺🇸"</span> },
  { <span class="hljs-attr">code</span>: <span class="hljs-string">"es"</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">"Español"</span>, <span class="hljs-attr">flag</span>: <span class="hljs-string">"🇪🇸"</span> },
  { <span class="hljs-attr">code</span>: <span class="hljs-string">"fr"</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">"Français"</span>, <span class="hljs-attr">flag</span>: <span class="hljs-string">"🇫🇷"</span> },
];

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">LanguageSwitcher</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { i18n } = useTranslation();

  <span class="hljs-keyword">const</span> changeLanguage = <span class="hljs-function">(<span class="hljs-params">languageCode</span>) =&gt;</span> {
    i18n.changeLanguage(languageCode);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
        <span class="hljs-attr">display:</span> "<span class="hljs-attr">flex</span>",
        <span class="hljs-attr">gap:</span> "<span class="hljs-attr">10px</span>",
        <span class="hljs-attr">padding:</span> "<span class="hljs-attr">10px</span>",
        <span class="hljs-attr">background:</span> "#<span class="hljs-attr">f5f5f5</span>",
        <span class="hljs-attr">borderRadius:</span> "<span class="hljs-attr">8px</span>",
      }}
    &gt;</span>
      {languages.map((lang) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">key</span>=<span class="hljs-string">{lang.code}</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> changeLanguage(lang.code)}
          style={{
            padding: "8px 16px",
            background: i18n.language === lang.code ? "#2196f3" : "#fff",
            color: i18n.language === lang.code ? "#fff" : "#000",
            border: "1px solid #ddd",
            borderRadius: "4px",
            cursor: "pointer",
            display: "flex",
            alignItems: "center",
            gap: "8px",
            fontSize: "14px",
            fontWeight: i18n.language === lang.code ? "bold" : "normal",
            transition: "all 0.2s ease",
          }}
        &gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{lang.flag}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{lang.name}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> LanguageSwitcher;
</code></pre>
<h3 id="heading-complete-app-with-language-switcher">Complete App with Language Switcher</h3>
<p>Here's a complete example showing the language switcher in action:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> LanguageSwitcher <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/LanguageSwitcher"</span>;
<span class="hljs-keyword">import</span> ProductCard <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/ProductCard"</span>;
<span class="hljs-keyword">import</span> UserProfile <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/UserProfile"</span>;

<span class="hljs-keyword">const</span> product = {
  <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Laptop"</span>,
  <span class="hljs-attr">price</span>: <span class="hljs-number">999</span>,
  <span class="hljs-attr">stock</span>: <span class="hljs-number">5</span>,
};

<span class="hljs-keyword">const</span> user = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">"John"</span>,
  <span class="hljs-attr">points</span>: <span class="hljs-number">150</span>,
};

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">header</span>
        <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
          <span class="hljs-attr">padding:</span> "<span class="hljs-attr">20px</span>",
          <span class="hljs-attr">background:</span> "#<span class="hljs-attr">fff</span>",
          <span class="hljs-attr">boxShadow:</span> "<span class="hljs-attr">0</span> <span class="hljs-attr">2px</span> <span class="hljs-attr">4px</span> <span class="hljs-attr">rgba</span>(<span class="hljs-attr">0</span>,<span class="hljs-attr">0</span>,<span class="hljs-attr">0</span>,<span class="hljs-attr">0.1</span>)",
          <span class="hljs-attr">marginBottom:</span> "<span class="hljs-attr">20px</span>",
        }}
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">LanguageSwitcher</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ProductCard</span> <span class="hljs-attr">product</span>=<span class="hljs-string">{product}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">UserProfile</span> <span class="hljs-attr">user</span>=<span class="hljs-string">{user}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>If you check the application you can see the working language switcher as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764930277307/d53d5f09-7712-4500-b39c-1d05f2820923.gif" alt class="image--center mx-auto" /></p>
<p><strong>Access The Ultimate React Ebooks Collection By Clicking The Image Below 👇</strong></p>
<p><strong><a target="_blank" href="https://www.dropbox.com/scl/fi/vnszyiunuk62xkspjf09k/12_Redux-Toolkit_Getting_Started.pdf?rlkey=yqrxqjfsqo7wbz8p7vka4ub63&amp;st=s024jf7j&amp;dl=0">Download The Complete Redux Toolkit Ebook Here</a></strong></p>
<p><a target="_blank" href="https://courses.yogeshchavan.dev/the-ultimate-react-ebooks-components-hooks-redux-routing-and-more"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765128444616/1bf15a77-a5f2-4cd1-9e7c-aa2bd6f120b5.png" alt class="image--center mx-auto" /></a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! You've learned how to build a fully internationalized React application.</p>
<p><strong>You can find the complete source code for this application <a target="_blank" href="https://github.com/myogeshchavan97/react-i18n-demo">in this repository</a>.</strong></p>
<p>In this tutorial, you learned:</p>
<ul>
<li><p>What internationalization (i18n) is and why it matters</p>
</li>
<li><p>How to set up react-i18next in your React app</p>
</li>
<li><p>How to organize translations in different files</p>
</li>
<li><p>How variables and interpolation work in translations</p>
</li>
<li><p>How to use the <code>useTranslation</code> hook for translations</p>
</li>
<li><p>How to handle pluralization automatically</p>
</li>
<li><p>How to format dates, numbers, and currencies for different locales</p>
</li>
<li><p>How to build a language switcher component</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[50+ React Pro Tips You Must Know For Better Coding]]></title><description><![CDATA[1. React Secret: The "Lazy Loading" Pattern for Instant Load Times
Your bundle is 2MB and users wait 8 seconds for first paint!
Code splitting with React.lazy() can cut that to 200KB and 1 second. This is non-negotiable for production apps.
The Probl...]]></description><link>https://blog.yogeshchavan.dev/50-react-pro-tips-you-must-know-for-better-coding</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/50-react-pro-tips-you-must-know-for-better-coding</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Next.js]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Sun, 30 Nov 2025 07:45:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1764488639245/ef9107c3-6398-4a41-8db0-e882d2056163.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-1-react-secret-the-lazy-loading-pattern-for-instant-load-times"><strong>1. React Secret: The "Lazy Loading" Pattern for Instant Load Times</strong></h2>
<p>Your bundle is 2MB and users wait 8 seconds for first paint!</p>
<p>Code splitting with React.lazy() can cut that to 200KB and 1 second. This is non-negotiable for production apps.</p>
<p><strong>The Problem:</strong></p>
<p>You're shipping EVERYTHING in one bundle. Users download code for routes they never visit.</p>
<pre><code class="lang-javascript">❌ Everything <span class="hljs-keyword">in</span> single Bundle:

<span class="hljs-comment">// App.js - imports EVERYTHING upfront</span>
<span class="hljs-keyword">import</span> Dashboard <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Dashboard'</span>;  <span class="hljs-comment">// 300 KB</span>
<span class="hljs-keyword">import</span> Analytics <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Analytics'</span>;  <span class="hljs-comment">// 450 KB</span>
<span class="hljs-keyword">import</span> Reports <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Reports'</span>;      <span class="hljs-comment">// 380 KB</span>
<span class="hljs-keyword">import</span> Settings <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Settings'</span>;    <span class="hljs-comment">// 250 KB</span>
<span class="hljs-keyword">import</span> AdminPanel <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/AdminPanel'</span>; <span class="hljs-comment">// 520 KB</span>
<span class="hljs-keyword">import</span> UserManagement <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/UserManagement'</span>; <span class="hljs-comment">// 400 KB</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Dashboard</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/analytics"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Analytics</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/reports"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Reports</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/settings"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Settings</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/admin"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">AdminPanel</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/users"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">UserManagement</span> /&gt;</span>} /&gt;
    <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// 🚨 Problem: User visits "/" → Downloads 2.3 MB!</span>
<span class="hljs-comment">// 😱 But only needs Dashboard (300 KB)!</span>
<span class="hljs-comment">// Wasted: 2 MB downloaded</span>
<span class="hljs-comment">// User waits: 8 seconds on 3G</span>
</code></pre>
<pre><code class="lang-javascript">✅ Code Splitting <span class="hljs-keyword">with</span> React.lazy():

<span class="hljs-keyword">import</span> { lazy, Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-comment">// ✨ Only import what you need, when you need it!</span>
<span class="hljs-keyword">const</span> Dashboard = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./pages/Dashboard'</span>));
<span class="hljs-keyword">const</span> Analytics = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./pages/Analytics'</span>));
<span class="hljs-keyword">const</span> Reports = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./pages/Reports'</span>));
<span class="hljs-keyword">const</span> Settings = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./pages/Settings'</span>));
<span class="hljs-keyword">const</span> AdminPanel = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./pages/AdminPanel'</span>));
<span class="hljs-keyword">const</span> UserManagement = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./pages/UserManagement'</span>));

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">LoadingSpinner</span> /&gt;</span>}&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Dashboard</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/analytics"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Analytics</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/reports"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Reports</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/settings"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Settings</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/admin"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">AdminPanel</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/users"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">UserManagement</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// ✨ User visits "/" → Downloads 300 KB only!</span>
<span class="hljs-comment">// Other routes load on-demand</span>
<span class="hljs-comment">// Initial load: 1 second on 3G! 🎉</span>
</code></pre>
<pre><code class="lang-javascript">🔥 Real Bundle Analysis:

✨Before Code Splitting:

npm run build

# Output:
File sizes after gzip:
  <span class="hljs-number">2.31</span> MB  build/<span class="hljs-keyword">static</span>/js/main.chunk.js  😱

# Lighthouse Score:
First Contentful Paint: <span class="hljs-number">8.2</span>s
Time to Interactive: <span class="hljs-number">12.4</span>s
Performance Score: <span class="hljs-number">34</span>/<span class="hljs-number">100</span> 🔴

✨After Code Splitting:

npm run build

# Output:
File sizes after gzip:
  <span class="hljs-number">187</span> KB  build/<span class="hljs-keyword">static</span>/js/main.chunk.js  ✨
  <span class="hljs-number">310</span> KB  build/<span class="hljs-keyword">static</span>/js/<span class="hljs-number">1.</span>chunk.js (Dashboard)
  <span class="hljs-number">445</span> KB  build/<span class="hljs-keyword">static</span>/js/<span class="hljs-number">2.</span>chunk.js (Analytics)
  <span class="hljs-number">375</span> KB  build/<span class="hljs-keyword">static</span>/js/<span class="hljs-number">3.</span>chunk.js (Reports)

# Lighthouse Score:
First Contentful Paint: <span class="hljs-number">1.2</span>s ⚡
Time to Interactive: <span class="hljs-number">2.1</span>s
Performance Score: <span class="hljs-number">94</span>/<span class="hljs-number">100</span> 🟢

<span class="hljs-number">12</span>x faster initial load!
</code></pre>
<pre><code class="lang-javascript">💪 Component-Level Code Splitting:

<span class="hljs-comment">// Don't just split routes - split heavy components!</span>

<span class="hljs-keyword">import</span> { lazy, Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-comment">// ✨ Lazy load heavy chart library only when needed</span>
<span class="hljs-keyword">const</span> Chart = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./components/HeavyChart'</span>));
<span class="hljs-keyword">const</span> DataTable = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./components/DataTable'</span>));
<span class="hljs-keyword">const</span> PdfViewer = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./components/PdfViewer'</span>));

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [showChart, setShowChart] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setShowChart(true)}&gt;
        Show Chart
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

      {showChart &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">ChartSkeleton</span> /&gt;</span>}&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Chart</span> <span class="hljs-attr">data</span>=<span class="hljs-string">{chartData}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Chart only loads when user clicks button! 🎉</span>
<span class="hljs-comment">// Saves 450 KB on initial load</span>
</code></pre>
<pre><code class="lang-javascript">🎯 Modal/Dialog Lazy Loading:

<span class="hljs-comment">// ❌ BAD - Modal code loaded even if never opened</span>
<span class="hljs-keyword">import</span> EditUserModal <span class="hljs-keyword">from</span> <span class="hljs-string">'./EditUserModal'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isModalOpen, setIsModalOpen] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">UserTable</span> /&gt;</span>
      {isModalOpen &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">EditUserModal</span> <span class="hljs-attr">onClose</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsModalOpen(false)} /&gt;}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// ✅ GOOD - Modal loads only when opened</span>
<span class="hljs-keyword">const</span> EditUserModal = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./EditUserModal'</span>));

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isModalOpen, setIsModalOpen] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">UserTable</span> /&gt;</span>

      {isModalOpen &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">ModalSkeleton</span> /&gt;</span>}&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">EditUserModal</span> <span class="hljs-attr">onClose</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsModalOpen(false)} /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Modal code only downloaded when user clicks "Edit"! ✨</span>
</code></pre>
<pre><code class="lang-javascript">🔥 Tab Content Lazy Loading:

<span class="hljs-keyword">const</span> OverviewTab = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./tabs/OverviewTab'</span>));
<span class="hljs-keyword">const</span> AnalyticsTab = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./tabs/AnalyticsTab'</span>));
<span class="hljs-keyword">const</span> SettingsTab = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./tabs/SettingsTab'</span>));

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [activeTab, setActiveTab] = useState(<span class="hljs-string">'overview'</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Tabs</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{activeTab}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{setActiveTab}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Tab</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"overview"</span>&gt;</span>Overview<span class="hljs-tag">&lt;/<span class="hljs-name">Tab</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Tab</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"analytics"</span>&gt;</span>Analytics<span class="hljs-tag">&lt;/<span class="hljs-name">Tab</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Tab</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"settings"</span>&gt;</span>Settings<span class="hljs-tag">&lt;/<span class="hljs-name">Tab</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Tabs</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">TabSkeleton</span> /&gt;</span>}&gt;
        {activeTab === 'overview' &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">OverviewTab</span> /&gt;</span>}
        {activeTab === 'analytics' &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">AnalyticsTab</span> /&gt;</span>}
        {activeTab === 'settings' &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">SettingsTab</span> /&gt;</span>}
      <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Each tab loads only when clicked! 🎉</span>
<span class="hljs-comment">// Initial load: Only active tab</span>
</code></pre>
<pre><code class="lang-javascript">💎 Library Lazy Loading:

<span class="hljs-comment">// ❌ BAD - Huge library loaded upfront</span>
<span class="hljs-keyword">import</span> Moment <span class="hljs-keyword">from</span> <span class="hljs-string">'moment'</span>;  <span class="hljs-comment">// 288 KB!</span>
<span class="hljs-keyword">import</span> Lodash <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash'</span>;  <span class="hljs-comment">// 71 KB!</span>
<span class="hljs-keyword">import</span> ChartJS <span class="hljs-keyword">from</span> <span class="hljs-string">'chart.js'</span>;  <span class="hljs-comment">// 210 KB!</span>

<span class="hljs-comment">// ✅ GOOD - Lazy load heavy libraries</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DatePicker</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [moment, setMoment] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// ✨ Load moment only when component mounts</span>
    <span class="hljs-keyword">import</span>(<span class="hljs-string">'moment'</span>).then(<span class="hljs-function"><span class="hljs-params">mod</span> =&gt;</span> setMoment(<span class="hljs-function">() =&gt;</span> mod.default));
  }, []);

  <span class="hljs-keyword">if</span> (!moment) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{moment().format('MMMM Do YYYY')}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

<span class="hljs-comment">// Even better: Use smaller alternatives</span>
<span class="hljs-comment">// moment (288 KB) → date-fns (13 KB)</span>
<span class="hljs-comment">// lodash (71 KB) → lodash-es with tree-shaking</span>
</code></pre>
<pre><code class="lang-javascript">✨ Preloading Strategy:

<span class="hljs-comment">// ✨ Preload routes user is likely to visit</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> preloadAnalytics = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">import</span>(<span class="hljs-string">'./pages/Analytics'</span>);  <span class="hljs-comment">// Start loading in background</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">nav</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> 
          <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span> 
          <span class="hljs-attr">onMouseEnter</span>=<span class="hljs-string">{preloadAnalytics}</span>  // ✨ <span class="hljs-attr">Preload</span> <span class="hljs-attr">on</span> <span class="hljs-attr">hover</span>!
        &gt;</span>
          Dashboard
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/analytics"</span>&gt;</span>Analytics<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">PageLoader</span> /&gt;</span>}&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Dashboard</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/analytics"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Analytics</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Hover over link → Starts loading</span>
<span class="hljs-comment">// Click link → Already loaded! Instant! ⚡️</span>
</code></pre>
<pre><code class="lang-javascript">🎯 Progressive Loading Pattern:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DashboardPage</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {/* ✨ Load critical content first */}
      <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">MainStats</span> /&gt;</span>

      {/* Load secondary content lazily */}
      <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">ChartSkeleton</span> /&gt;</span>}&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">LazyChart</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">TableSkeleton</span> /&gt;</span>}&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">LazyDataTable</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">WidgetSkeleton</span> /&gt;</span>}&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">LazyWidgets</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Page appears instantly with skeletons</span>
<span class="hljs-comment">// Content loads progressively as chunks arrive! 🎨</span>
</code></pre>
<pre><code class="lang-javascript">🔥 Nested Suspense Boundaries:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="hljs-comment">// ✨ Outer Suspense for route-level loading</span>
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">AppLoader</span> /&gt;</span>}&gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Dashboard</span> /&gt;</span>} /&gt;
      <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

      {/* ✨ Inner Suspense for component-level loading */}
      <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Skeleton</span> /&gt;</span>}&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">HeavyChart</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Skeleton</span> /&gt;</span>}&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">DataTable</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Route switches → Show AppLoader</span>
<span class="hljs-comment">// Components load → Show individual Skeletons</span>
<span class="hljs-comment">// Better UX! ✨</span>
</code></pre>
<pre><code class="lang-javascript">🚨 Common Mistakes:

<span class="hljs-comment">// ❌ MISTAKE #1: Forgetting Suspense</span>
<span class="hljs-keyword">const</span> Dashboard = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./Dashboard'</span>));
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Dashboard</span> /&gt;</span></span>  <span class="hljs-comment">// ERROR! Must wrap in Suspense</span>

<span class="hljs-comment">// ✅ FIX:</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Loading</span> /&gt;</span>}&gt;
  <span class="hljs-tag">&lt;<span class="hljs-name">Dashboard</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span></span>

<span class="hljs-comment">// ❌ MISTAKE #2: Lazy loading tiny components</span>
<span class="hljs-keyword">const</span> Button = lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./Button'</span>));  <span class="hljs-comment">// 2 KB component</span>
<span class="hljs-comment">// Overhead of loading &gt; component size!</span>

<span class="hljs-comment">// ✅ FIX: Only lazy load components &gt; 20 KB</span>

<span class="hljs-comment">// ❌ MISTAKE #3: No loading state</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{null}</span>&gt;</span>  // Blank screen during load!
  <span class="hljs-tag">&lt;<span class="hljs-name">HeavyComponent</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span></span>

<span class="hljs-comment">// ✅ FIX: Always show loading UI</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Skeleton</span> /&gt;</span>}&gt;
  <span class="hljs-tag">&lt;<span class="hljs-name">HeavyComponent</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span></span>

📊 Real Results:

E-commerce App (Before):
├─ Bundle size: <span class="hljs-number">2.8</span> MB
├─ Load time (<span class="hljs-number">3</span>G): <span class="hljs-number">11</span> seconds
├─ Bounce rate: <span class="hljs-number">53</span>%
└─ Lighthouse: <span class="hljs-number">28</span>/<span class="hljs-number">100</span>

E-commerce App (After lazy loading):
├─ Initial bundle: <span class="hljs-number">340</span> KB
├─ Load time (<span class="hljs-number">3</span>G): <span class="hljs-number">1.4</span> seconds
├─ Bounce rate: <span class="hljs-number">19</span>%
└─ Lighthouse: <span class="hljs-number">92</span>/<span class="hljs-number">100</span>

<span class="hljs-attr">Result</span>:
├─ <span class="hljs-number">8</span>x smaller initial bundle
├─ <span class="hljs-number">8</span>x faster load time
├─ <span class="hljs-number">64</span>% reduction <span class="hljs-keyword">in</span> bounce rate
└─ Revenue increased <span class="hljs-number">34</span>%! 💰
</code></pre>
<hr />
<h2 id="heading-2-react-performance-secret-the-bail-out-optimization-pattern"><strong>2. React Performance Secret: The "Bail Out" Optimization Pattern</strong></h2>
<p>This ONE weird trick makes React skip re-rendering entirely.</p>
<p><strong>The Hidden React Behavior:</strong></p>
<p>If you return the EXACT same state object, React bails out of rendering. Not just memo() - this works at the state level. Your component AND its children won't re-render.</p>
<pre><code class="lang-javascript">💡 The Magic:

❌ This ALWAYS Re-renders:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [users, setUsers] = useState([]);

  <span class="hljs-keyword">const</span> addUser = <span class="hljs-function">(<span class="hljs-params">newUser</span>) =&gt;</span> {
    <span class="hljs-comment">// Even if user already exists, this triggers re-render!</span>
    setUsers([...users, newUser]);
  };

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ExpensiveList</span> <span class="hljs-attr">users</span>=<span class="hljs-string">{users}</span> /&gt;</span></span>;
}
</code></pre>
<pre><code class="lang-javascript">✅ Smart Bail Out Pattern:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [users, setUsers] = useState([]);

  <span class="hljs-keyword">const</span> addUser = <span class="hljs-function">(<span class="hljs-params">newUser</span>) =&gt;</span> {
    setUsers(<span class="hljs-function"><span class="hljs-params">prevUsers</span> =&gt;</span> {
      <span class="hljs-comment">// If user exists, return SAME array reference</span>
      <span class="hljs-keyword">if</span> (prevUsers.some(<span class="hljs-function"><span class="hljs-params">u</span> =&gt;</span> u.id === newUser.id)) {
        <span class="hljs-keyword">return</span> prevUsers;  <span class="hljs-comment">// 🚀 React skips render!</span>
      }
      <span class="hljs-keyword">return</span> [...prevUsers, newUser];
    });
  };

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ExpensiveList</span> <span class="hljs-attr">users</span>=<span class="hljs-string">{users}</span> /&gt;</span></span>;
}
</code></pre>
<pre><code class="lang-javascript">🔥 Advanced: Conditional Updates Only:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FilteredProducts</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [filters, setFilters] = useState({
    <span class="hljs-attr">category</span>: <span class="hljs-string">'all'</span>,
    <span class="hljs-attr">priceRange</span>: [<span class="hljs-number">0</span>, <span class="hljs-number">1000</span>],
    <span class="hljs-attr">inStock</span>: <span class="hljs-literal">false</span>
  });

  <span class="hljs-keyword">const</span> updateFilter = <span class="hljs-function">(<span class="hljs-params">key, value</span>) =&gt;</span> {
    setFilters(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> {
      <span class="hljs-comment">// Bail out if value hasn't actually changed</span>
      <span class="hljs-keyword">if</span> (prev[key] === value) {
        <span class="hljs-keyword">return</span> prev;  <span class="hljs-comment">// ✨ No render if nothing changed!</span>
      }
      <span class="hljs-keyword">return</span> { ...prev, [key]: value };
    });
  };

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ProductGrid</span> <span class="hljs-attr">filters</span>=<span class="hljs-string">{filters}</span> /&gt;</span></span>;
}
</code></pre>
<pre><code class="lang-javascript">💪 Real-World: Smart Form State:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useSmartForm</span>(<span class="hljs-params">initialValues</span>) </span>{
  <span class="hljs-keyword">const</span> [values, setValues] = useState(initialValues);
  <span class="hljs-keyword">const</span> [errors, setErrors] = useState({});

  <span class="hljs-keyword">const</span> updateField = useCallback(<span class="hljs-function">(<span class="hljs-params">name, value</span>) =&gt;</span> {
    setValues(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> {
      <span class="hljs-comment">// Deep equality check - bail if truly unchanged</span>
      <span class="hljs-keyword">if</span> (<span class="hljs-built_in">JSON</span>.stringify(prev[name]) === <span class="hljs-built_in">JSON</span>.stringify(value)) {
        <span class="hljs-keyword">return</span> prev;  <span class="hljs-comment">// 🎯 Skip unnecessary validations!</span>
      }

      <span class="hljs-keyword">return</span> { ...prev, [name]: value };
    });
  }, []);

  <span class="hljs-keyword">return</span> { values, updateField, errors };
}

<span class="hljs-comment">// Usage:</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProfileForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { values, updateField } = useSmartForm({
    <span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span>,
    <span class="hljs-attr">email</span>: <span class="hljs-string">'john@example.com'</span>
  });

  <span class="hljs-comment">// Typing same value won't trigger re-render! 🎉</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
      <span class="hljs-attr">value</span>=<span class="hljs-string">{values.name}</span>
      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> updateField('name', e.target.value)}
    /&gt;</span>
  );
}
</code></pre>
<pre><code class="lang-javascript">🔥 Bonus: API Calls With Bail Out:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useDataFetch</span>(<span class="hljs-params">url</span>) </span>{
  <span class="hljs-keyword">const</span> [data, setData] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> fetchData = useCallback(<span class="hljs-keyword">async</span> () =&gt; {
    setLoading(<span class="hljs-literal">true</span>);

    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> fetch(url);
    <span class="hljs-keyword">const</span> json = <span class="hljs-keyword">await</span> result.json();

    setData(<span class="hljs-function"><span class="hljs-params">prevData</span> =&gt;</span> {
      <span class="hljs-comment">// Don't update if data is identical</span>
      <span class="hljs-keyword">if</span> (<span class="hljs-built_in">JSON</span>.stringify(prevData) === <span class="hljs-built_in">JSON</span>.stringify(json)) {
        <span class="hljs-keyword">return</span> prevData;  <span class="hljs-comment">// 🎯 Skip render + child updates!</span>
      }
      <span class="hljs-keyword">return</span> json;
    });

    setLoading(<span class="hljs-literal">false</span>);
  }, [url]);

  <span class="hljs-keyword">return</span> { data, loading, fetchData };
}
</code></pre>
<pre><code class="lang-javascript">📊 The Performance Impact:

🚀 Eliminates <span class="hljs-number">30</span><span class="hljs-number">-50</span>% <span class="hljs-keyword">of</span> unnecessary renders
⚡ Fewer child component updates
💰 Reduced React reconciliation work
🎮 Smoother UI, especially <span class="hljs-keyword">in</span> forms and lists
</code></pre>
<p><strong>PS:</strong> Don't add bail-out condition using JSON.stringify initially itself while writing code as comparing using JSON.stringify is slower for larger objects. Use this as an optimization step.</p>
<hr />
<h2 id="heading-3-react-anti-pattern-usestate-for-derived-data-mistake"><strong>3. React Anti-Pattern: "useState for Derived Data" Mistake</strong></h2>
<p>If you can calculate it from existing state/props, DON'T put it in useState.</p>
<p>This bug pattern creates sync issues that haunt production.</p>
<p><strong>The Problem:</strong></p>
<p>Storing calculated/derived values in state creates two sources of truth. They get out of sync, causing difficult-to-debug issues.</p>
<pre><code class="lang-javascript">❌ The Anti-Pattern (Double State):

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ShoppingCart</span>(<span class="hljs-params">{ items }</span>) </span>{
  <span class="hljs-keyword">const</span> [cartItems, setCartItems] = useState(items);
  <span class="hljs-keyword">const</span> [totalPrice, setTotalPrice] = useState(<span class="hljs-number">0</span>);  <span class="hljs-comment">// 🚨 Derived!</span>
  <span class="hljs-keyword">const</span> [itemCount, setItemCount] = useState(<span class="hljs-number">0</span>);    <span class="hljs-comment">// 🚨 Derived!</span>
  <span class="hljs-keyword">const</span> [hasDiscount, setHasDiscount] = useState(<span class="hljs-literal">false</span>);  <span class="hljs-comment">// 🚨 Derived!</span>

  <span class="hljs-comment">// 🚨 Must remember to update ALL state together</span>
  <span class="hljs-keyword">const</span> addItem = <span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> newItems = [...cartItems, item];
    setCartItems(newItems);
    setTotalPrice(calculateTotal(newItems));  <span class="hljs-comment">// Easy to forget!</span>
    setItemCount(newItems.length);
    setHasDiscount(calculateTotal(newItems) &gt; <span class="hljs-number">100</span>);
  };

  <span class="hljs-comment">// 😱 <span class="hljs-doctag">BUG:</span> What if you forget to update one?</span>
  <span class="hljs-comment">// totalPrice and itemCount are now OUT OF SYNC!</span>

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Items: {itemCount}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Total: ${totalPrice}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      {hasDiscount &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Discount applied!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<pre><code class="lang-javascript">✅ The Correct Way (Single Source <span class="hljs-keyword">of</span> Truth):

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ShoppingCart</span>(<span class="hljs-params">{ items }</span>) </span>{
 <span class="hljs-keyword">const</span> [cartItems, setCartItems] = useState(items);

  <span class="hljs-comment">// ✨ Calculate derived values - always in sync!</span>
 <span class="hljs-keyword">const</span> totalPrice = cartItems.reduce(<span class="hljs-function">(<span class="hljs-params">sum, item</span>) =&gt;</span> sum + item.price, <span class="hljs-number">0</span>);
 <span class="hljs-keyword">const</span> itemCount = cartItems.length;
 <span class="hljs-keyword">const</span> hasDiscount = totalPrice &gt; <span class="hljs-number">100</span>;

 <span class="hljs-comment">// ✨ Only update ONE state - everything else auto-updates!</span>
 <span class="hljs-keyword">const</span> addItem = <span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
   setCartItems([...cartItems, item]);
   <span class="hljs-comment">// That's it! No need to update anything else! 🎉</span>
 };

 <span class="hljs-keyword">return</span> (
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Items: {itemCount}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Total: ${totalPrice}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      {hasDiscount &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Discount applied!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
   <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<pre><code class="lang-javascript">✨ Common Derived State Examples:

<span class="hljs-number">1.</span> Filtered Lists:

<span class="hljs-comment">// ❌ BAD - Double state</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductList</span>(<span class="hljs-params">{ products }</span>) </span>{
  <span class="hljs-keyword">const</span> [searchTerm, setSearchTerm] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [filteredProducts, setFilteredProducts] = useState(products);  <span class="hljs-comment">// 🚨 Derived!</span>

  <span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">(<span class="hljs-params">term</span>) =&gt;</span> {
    setSearchTerm(term);
    setFilteredProducts(products.filter(<span class="hljs-function"><span class="hljs-params">p</span> =&gt;</span> p.name.includes(term)));  <span class="hljs-comment">// Can get out of sync!</span>
  };

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

<span class="hljs-comment">// ✅ GOOD - Single source</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductList</span>(<span class="hljs-params">{ products }</span>) </span>{
  <span class="hljs-keyword">const</span> [searchTerm, setSearchTerm] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-comment">// ✨ Always calculated from current values</span>
  <span class="hljs-keyword">const</span> filteredProducts = products.filter(<span class="hljs-function"><span class="hljs-params">p</span> =&gt;</span>
    p.name.toLowerCase().includes(searchTerm.toLowerCase())
  );

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<pre><code class="lang-javascript">✨ Common Derived State Examples:

<span class="hljs-number">2.</span> Form Validation:

<span class="hljs-comment">// ❌ BAD - Validation state separate</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SignupForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [isValid, setIsValid] = useState(<span class="hljs-literal">false</span>);  <span class="hljs-comment">// 🚨 Derived!</span>

  <span class="hljs-keyword">const</span> handleEmailChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    setEmail(e.target.value);
    <span class="hljs-comment">// 😱 Forgot to update isValid!</span>
  };

  <span class="hljs-keyword">const</span> handlePasswordChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    setPassword(e.target.value);
    setIsValid(password.length &gt;= <span class="hljs-number">8</span> &amp;&amp; email.includes(<span class="hljs-string">'@'</span>));  <span class="hljs-comment">// Out of sync!</span>
  };

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">disabled</span>=<span class="hljs-string">{!isValid}</span>&gt;</span>Sign Up<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
}

<span class="hljs-comment">// ✅ GOOD - Validation derived</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SignupForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [email, setEmail] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-comment">// ✨ Always accurate</span>
  <span class="hljs-keyword">const</span> isEmailValid = email.includes(<span class="hljs-string">'@'</span>);
  <span class="hljs-keyword">const</span> isPasswordValid = password.length &gt;= <span class="hljs-number">8</span>;
  <span class="hljs-keyword">const</span> isFormValid = isEmailValid &amp;&amp; isPasswordValid;

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">disabled</span>=<span class="hljs-string">{!isFormValid}</span>&gt;</span>Sign Up<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
}
</code></pre>
<pre><code class="lang-javascript">✨ Common Derived State Examples:

<span class="hljs-number">3.</span> Totals &amp; Calculations:

<span class="hljs-comment">// ❌ BAD - Sync nightmare</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Invoice</span>(<span class="hljs-params">{ items }</span>) </span>{
  <span class="hljs-keyword">const</span> [invoiceItems, setInvoiceItems] = useState(items);
  <span class="hljs-keyword">const</span> [subtotal, setSubtotal] = useState(<span class="hljs-number">0</span>);  <span class="hljs-comment">// 🚨 Derived!</span>
  <span class="hljs-keyword">const</span> [tax, setTax] = useState(<span class="hljs-number">0</span>);            <span class="hljs-comment">// 🚨 Derived!</span>
  <span class="hljs-keyword">const</span> [total, setTotal] = useState(<span class="hljs-number">0</span>);        <span class="hljs-comment">// 🚨 Derived!</span>

  <span class="hljs-keyword">const</span> addItem = <span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> newItems = [...invoiceItems, item];
    <span class="hljs-keyword">const</span> newSubtotal = calculateSubtotal(newItems);
    <span class="hljs-keyword">const</span> newTax = newSubtotal * <span class="hljs-number">0.1</span>;

    setInvoiceItems(newItems);
    setSubtotal(newSubtotal);
    setTax(newTax);
    setTotal(newSubtotal + newTax);

    <span class="hljs-comment">// 😱 So many places to make mistakes!</span>
  };

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Total: ${total}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

<span class="hljs-comment">// ✅ GOOD - Single calculation</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Invoice</span>(<span class="hljs-params">{ items }</span>) </span>{
  <span class="hljs-keyword">const</span> [invoiceItems, setInvoiceItems] = useState(items);

  <span class="hljs-comment">// ✨ All calculated from ONE source</span>
  <span class="hljs-keyword">const</span> subtotal = invoiceItems.reduce(<span class="hljs-function">(<span class="hljs-params">sum, item</span>) =&gt;</span> sum + item.price, <span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> tax = subtotal * <span class="hljs-number">0.1</span>;
  <span class="hljs-keyword">const</span> total = subtotal + tax;

  <span class="hljs-keyword">const</span> addItem = <span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
    setInvoiceItems([...invoiceItems, item]);
    <span class="hljs-comment">// ✨ Done! Everything else updates automatically!</span>
  };

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Total: ${total.toFixed(2)}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<pre><code class="lang-javascript">🎯 Performance Concern? Use useMemo:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DataDashboard</span>(<span class="hljs-params">{ transactions }</span>) </span>{
  <span class="hljs-keyword">const</span> [dateRange, setDateRange] = useState(<span class="hljs-string">'month'</span>);
  <span class="hljs-keyword">const</span> [category, setCategory] = useState(<span class="hljs-string">'all'</span>);

  <span class="hljs-comment">// ✨ Expensive calculation? Memoize it!</span>
  <span class="hljs-keyword">const</span> filteredTransactions = useMemo(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> transactions
      .filter(<span class="hljs-function"><span class="hljs-params">t</span> =&gt;</span> matchesDateRange(t, dateRange))
      .filter(<span class="hljs-function"><span class="hljs-params">t</span> =&gt;</span> category === <span class="hljs-string">'all'</span> || t.category === category);
  }, [transactions, dateRange, category]);

  <span class="hljs-keyword">const</span> totalAmount = useMemo(<span class="hljs-function">() =&gt;</span> 
    filteredTransactions.reduce(<span class="hljs-function">(<span class="hljs-params">sum, t</span>) =&gt;</span> sum + t.amount, <span class="hljs-number">0</span>),
    [filteredTransactions]
  );

  <span class="hljs-keyword">const</span> averageAmount = totalAmount / filteredTransactions.length || <span class="hljs-number">0</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Total: ${totalAmount}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Average: ${averageAmount.toFixed(2)}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Count: {filteredTransactions.length}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<pre><code class="lang-javascript">💎 The Golden Rules:

<span class="hljs-comment">// Ask yourself: "Can I calculate this from other state/props?"</span>

<span class="hljs-comment">// If YES → Don't use useState!</span>
<span class="hljs-keyword">const</span> fullName = <span class="hljs-string">`<span class="hljs-subst">${firstName}</span> <span class="hljs-subst">${lastName}</span>`</span>;  <span class="hljs-comment">// ✅ Derived</span>
<span class="hljs-keyword">const</span> isValid = email.includes(<span class="hljs-string">'@'</span>);          <span class="hljs-comment">// ✅ Derived</span>
<span class="hljs-keyword">const</span> total = items.reduce(...);              <span class="hljs-comment">// ✅ Derived</span>

<span class="hljs-comment">// If NO → Use useState</span>
<span class="hljs-keyword">const</span> [firstName, setFirstName] = useState(<span class="hljs-string">''</span>);  <span class="hljs-comment">// ✅ User input</span>
<span class="hljs-keyword">const</span> [isModalOpen, setIsModalOpen] = useState(<span class="hljs-literal">false</span>);  <span class="hljs-comment">// ✅ UI state</span>
<span class="hljs-keyword">const</span> [data, setData] = useState(<span class="hljs-literal">null</span>);  <span class="hljs-comment">// ✅ Fetched data</span>
</code></pre>
<pre><code class="lang-javascript">🚨 Red Flags - You Probably Have Derived State:

<span class="hljs-comment">// 🚨 Red Flag #1: Multiple setState calls together</span>
<span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">() =&gt;</span> {
  setState1(newValue);
  setState2(calculateFromNewValue);  <span class="hljs-comment">// Derived!</span>
  setState3(calculateOther);  <span class="hljs-comment">// Derived!</span>
};

<span class="hljs-comment">// 🚨 Red Flag #2: useEffect to sync states</span>
useEffect(<span class="hljs-function">() =&gt;</span> {
  setDerivedValue(calculate(sourceValue));
}, [sourceValue]);  <span class="hljs-comment">// Just calculate it directly!</span>

<span class="hljs-comment">// 🚨 Red Flag #3: State that depends on other state</span>
<span class="hljs-keyword">const</span> [total, setTotal] = useState(<span class="hljs-number">0</span>);
<span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);
<span class="hljs-keyword">const</span> [average, setAverage] = useState(<span class="hljs-number">0</span>);  <span class="hljs-comment">// total / count = derived!</span>

📊 Comparison:

<span class="hljs-comment">// With Derived State (useState):</span>
✖ <span class="hljs-number">4</span> useState calls
✖ Must update <span class="hljs-number">4</span> states together
✖ Easy to forget one → bugs!
✖ Hard to maintain
✖ Out <span class="hljs-keyword">of</span> sync bugs <span class="hljs-keyword">in</span> production

<span class="hljs-comment">// Without Derived State (calculate):</span>
✅ <span class="hljs-number">1</span> useState call
✅ Update <span class="hljs-number">1</span> state, rest auto-updates
✅ Impossible to get out <span class="hljs-keyword">of</span> sync
✅ Easy to maintain
✅ No sync bugs possible
</code></pre>
<pre><code class="lang-javascript">🎯 Real Production Bug - Fixed:

<span class="hljs-comment">// The Bug</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">CheckoutForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [items, setItems] = useState([]);
  <span class="hljs-keyword">const</span> [total, setTotal] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">const</span> addItem = <span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
    setItems([...items, item]);
    <span class="hljs-comment">// 😱 Forgot to update total!</span>
  };

  <span class="hljs-comment">// User sees $0 total, thinks checkout is broken!</span>
}

<span class="hljs-comment">// The Fix:</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">CheckoutForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [items, setItems] = useState([]);
  <span class="hljs-keyword">const</span> total = items.reduce(<span class="hljs-function">(<span class="hljs-params">sum, item</span>) =&gt;</span> sum + item.price, <span class="hljs-number">0</span>);

  <span class="hljs-keyword">const</span> addItem = <span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
    setItems([...items, item]);
    <span class="hljs-comment">// ✨ Total automatically updates!</span>
  };
}
</code></pre>
<hr />
<h2 id="heading-4-best-reactnextjs-tool-the-knip-dead-code-eliminator"><strong>4. Best React/Next.js Tool: The "Knip" Dead Code Eliminator</strong></h2>
<p>Your codebase has 1000+ unused files and imports you don't even know about!</p>
<p>Knip finds them ALL in 10 seconds. This tool is a game-changer!</p>
<p><strong>The Problem:</strong></p>
<p>Dead code accumulates over time. Unused files, unused exports, orphaned components - they slow builds, confuse developers, and waste time!</p>
<pre><code class="lang-javascript">❌ Manual Cleanup (Impossible):

# Your project:
src/
├── components/
│   ├── Button.jsx           # Used? 🤔
│   ├── OldButton.jsx        # Used? 🤔
│   ├── LegacyModal.jsx      # Used? 🤔
│   ├── DeprecatedForm.jsx   # Used? 🤔
│   └── ... <span class="hljs-number">500</span> more files

# Manually checking each file? 😱
# Takes weeks, error-prone, nobody does it!
</code></pre>
<pre><code class="lang-javascript">✅ Knip to the Rescue (Automated!):

# Install Knip
npm install -D knip

# Run it
npx knip

# Output - BOOM! 💥
✖ Unused files (<span class="hljs-number">47</span>)
  src/components/OldButton.jsx
  src/components/LegacyModal.jsx
  src/components/DeprecatedForm.jsx
  src/utils/oldHelpers.js
  ... <span class="hljs-number">43</span> more files

✖ Unused dependencies (<span class="hljs-number">12</span>)
  lodash-es (<span class="hljs-keyword">in</span> package.json)
  moment (<span class="hljs-keyword">in</span> package.json)
  ... <span class="hljs-number">10</span> more

✖ Unused <span class="hljs-built_in">exports</span> (<span class="hljs-number">156</span>)
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> oldFunction (src/utils/helpers.js)
  <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deprecatedHook (src/hooks/useOldApi.js)
  ... <span class="hljs-number">154</span> more

Total wasted: <span class="hljs-number">47</span> files, <span class="hljs-number">12</span> dependencies, <span class="hljs-number">156</span> <span class="hljs-built_in">exports</span>
Potential savings: <span class="hljs-number">2.3</span> MB bundle size 🚀
</code></pre>
<pre><code class="lang-javascript">🔥 Real Example - Before/After:

Before Running Knip:

My React project:
- <span class="hljs-number">1</span>,<span class="hljs-number">247</span> files
- <span class="hljs-number">89</span> npm packages
- <span class="hljs-number">15.2</span> MB node_modules
- <span class="hljs-number">487</span> KB production bundle
- Build time: <span class="hljs-number">45</span> seconds
- <span class="hljs-string">"Which components are actually used?"</span> 🤷‍♂️

After Running Knip:

npx knip

# Found:
# - <span class="hljs-number">47</span> unused files
# - <span class="hljs-number">12</span> unused dependencies
# - <span class="hljs-number">156</span> unused <span class="hljs-built_in">exports</span>
# - <span class="hljs-number">23</span> duplicate <span class="hljs-built_in">exports</span>

# Cleaned up:
✅ Deleted <span class="hljs-number">47</span> unused files
✅ Removed <span class="hljs-number">12</span> unused packages
✅ Removed <span class="hljs-number">156</span> unused <span class="hljs-built_in">exports</span>
✅ Fixed <span class="hljs-number">23</span> duplicates

My React project now:
- <span class="hljs-number">1</span>,<span class="hljs-number">200</span> files (<span class="hljs-number">47</span> less!)
- <span class="hljs-number">77</span> npm packages (<span class="hljs-number">12</span> less!)
- <span class="hljs-number">12.8</span> MB node_modules (<span class="hljs-number">2.4</span> MB saved!)
- <span class="hljs-number">412</span> KB production bundle (<span class="hljs-number">75</span> KB saved!)
- Build time: <span class="hljs-number">38</span> seconds (<span class="hljs-number">7</span>s faster!)
- Clean, confident codebase! ✨
</code></pre>
<pre><code class="lang-javascript">✅ What Knip Finds:

<span class="hljs-number">1.</span> Unused Files:

✖ src/components/OldButton.jsx
  → Not imported anywhere
  → Safe to <span class="hljs-keyword">delete</span>! 🗑️

✖ src/pages/BetaFeature.jsx
  → Not <span class="hljs-keyword">in</span> routes
  → Remove or add to router

✖ src/utils/deprecatedHelpers.js
  → No imports found
  → Delete it!

<span class="hljs-number">2.</span> Unused Dependencies:

✖ lodash (<span class="hljs-keyword">in</span> package.json)
  → Never imported
  → npm uninstall lodash
  → Save <span class="hljs-number">72</span> KB!

✖ moment (<span class="hljs-keyword">in</span> package.json)
  → Replaced <span class="hljs-keyword">with</span> date-fns
  → npm uninstall moment
  → Save <span class="hljs-number">231</span> KB!

✖ react-router-dom v5 (<span class="hljs-keyword">in</span> package.json)
  → Upgraded to v6, forgot to remove
  → npm uninstall react-router-dom@<span class="hljs-number">5</span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-number">3.</span> Unused Exports:

<span class="hljs-comment">// src/utils/helpers.ts</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> oldFunction = <span class="hljs-function">() =&gt;</span> {};  <span class="hljs-comment">// ✖ Never imported</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> deprecatedUtil = <span class="hljs-function">() =&gt;</span> {};  <span class="hljs-comment">// ✖ Never imported</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> usedFunction = <span class="hljs-function">() =&gt;</span> {};  <span class="hljs-comment">// ✅ Used in 12 places</span>

<span class="hljs-comment">// Knip tells you: Remove first two exports!</span>

<span class="hljs-number">4.</span> Duplicate Exports:

<span class="hljs-comment">// ✖ src/components/Button/index.ts</span>
<span class="hljs-keyword">export</span> { Button } <span class="hljs-keyword">from</span> <span class="hljs-string">'./Button'</span>;

<span class="hljs-comment">// ✖ src/components/index.ts  </span>
<span class="hljs-keyword">export</span> { Button } <span class="hljs-keyword">from</span> <span class="hljs-string">'./Button'</span>;  <span class="hljs-comment">// Duplicate!</span>

<span class="hljs-comment">// Knip warns: Same export in multiple places!</span>

<span class="hljs-number">5.</span> Unlisted Dependencies:

<span class="hljs-comment">// src/App.tsx</span>
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;  <span class="hljs-comment">// ✖ Not in package.json!</span>

<span class="hljs-comment">// Knip says: Add axios to dependencies!</span>

📦 Knip Works With:

✅ React
✅ Next.js
✅ Remix
✅ Vite
✅ TypeScript
✅ JavaScript
✅ Turborepo/Nx (monorepos)
✅ Webpack/Rollup/esbuild
</code></pre>
<h3 id="heading-enjoying-these-tips-download-the-complete-collection-of-50-react-pro-tips-ebookhttpscoursesyogeshchavandevreact-50-pro-tips-ebook"><em>Enjoying these tips? Download the complete collection of</em> <a target="_blank" href="https://courses.yogeshchavan.dev/react-50-pro-tips-ebook"><em>50+ React Pro Tips Ebook</em></a><em>.</em></h3>
<hr />
<h2 id="heading-5-react-security-disaster-the-env-variables"><strong>5. React Security Disaster: The "ENV Variables"</strong></h2>
<p>Your .env file is leaking API keys into the frontend bundle!</p>
<p>Every user can see your secrets in 10 seconds. This mistake costs companies MILLIONS in stolen API credits.</p>
<p><strong>The Problem:</strong></p>
<p>React embeds ALL env variables starting with REACT_APP_ or VITE_ directly into your JavaScript bundle. Anyone can read them!</p>
<pre><code class="lang-javascript">❌ The Security Nightmare:

# .env file
REACT_APP_API_KEY=sk_live_51HxT8fhj3k2l...  # 🚨 EXPOSED!
REACT_APP_STRIPE_SECRET=sk_test_xyz123...    # 🚨 EXPOSED!
REACT_APP_DATABASE_URL=mongodb:<span class="hljs-comment">//admin:pass@... # 🚨 EXPOSED!</span>
REACT_APP_AWS_SECRET_KEY=AKIAI...            # 🚨 EXPOSED!

<span class="hljs-comment">// Your React code</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> apiKey = process.env.REACT_APP_API_KEY;  <span class="hljs-comment">// 🚨 In bundle!</span>

  fetch(<span class="hljs-string">'https://api.stripe.com/charges'</span>, {
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Authorization'</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${apiKey}</span>`</span>
    }
  });
}

<span class="hljs-comment">// What users see in browser DevTools → Sources → main.js:</span>
<span class="hljs-comment">// const apiKey = "sk_live_51HxT8fhj3k2l...";  😱</span>
<span class="hljs-comment">// Copy → Paste → FREE API ACCESS!</span>
<span class="hljs-comment">// Your keys are PUBLIC! 💀</span>
</code></pre>
<pre><code class="lang-javascript">🔥 How Hackers Find Your Keys:

# Method <span class="hljs-number">1</span>: View source
# Right-click → View Page Source
# Search <span class="hljs-keyword">for</span>: <span class="hljs-string">"api"</span>, <span class="hljs-string">"key"</span>, <span class="hljs-string">"secret"</span>, <span class="hljs-string">"token"</span>
# Found <span class="hljs-keyword">in</span> <span class="hljs-number">3</span> seconds! 😱

# Method <span class="hljs-number">2</span>: Check bundle files
# DevTools → Sources → <span class="hljs-keyword">static</span>/js/main.chunk.js
# Search <span class="hljs-keyword">for</span>: <span class="hljs-string">"REACT_APP_"</span>
# All your env variables visible! 💀

# Method <span class="hljs-number">3</span>: Automated scanning
# Hackers run scripts that:
# <span class="hljs-number">1.</span> Download your main.js
# <span class="hljs-number">2.</span> Search <span class="hljs-keyword">for</span> patterns (sk_live_, api_key, etc.)
# <span class="hljs-number">3.</span> Extract all secrets
# <span class="hljs-number">4.</span> Use your API <span class="hljs-keyword">for</span> free!

# Result:
# - $<span class="hljs-number">50</span>K Stripe bill <span class="hljs-keyword">from</span> unauthorized charges
# - AWS account compromised
# - Database exposed
# - Company bankrupt! 🔥
</code></pre>
<pre><code class="lang-javascript">✅ What<span class="hljs-string">'s Safe vs Unsafe:

# SAFE - Public information (goes in .env)

REACT_APP_API_URL=https://api.myapp.com  # Public endpoint ✅
REACT_APP_APP_VERSION=1.2.3              # Version number ✅
REACT_APP_FEATURE_FLAG_X=true            # Feature flag ✅
REACT_APP_GOOGLE_MAPS_KEY=AIza...        # Public API key* ✅
REACT_APP_SENTRY_DSN=https://...         # Public DSN ✅

# UNSAFE - Secrets (NEVER in frontend!)

REACT_APP_STRIPE_SECRET_KEY=sk_live_...  # SECRET! 🚨
REACT_APP_DATABASE_PASSWORD=mysecret123  # SECRET! 🚨
REACT_APP_JWT_SECRET=supersecret         # SECRET! 🚨
REACT_APP_OPENAI_API_KEY=sk-proj-...     # SECRET! 🚨
REACT_APP_AWS_SECRET=AKIAI...            # SECRET! 🚨</span>
</code></pre>
<pre><code class="lang-javascript">💪 The Correct Architecture:

<span class="hljs-comment">// ❌ WRONG - Secret in frontend</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Payment</span>(<span class="hljs-params">{ amount }</span>) </span>{
  <span class="hljs-keyword">const</span> stripeSecret = process.env.REACT_APP_STRIPE_SECRET;  <span class="hljs-comment">// 🚨 EXPOSED!</span>

  fetch(<span class="hljs-string">'https://api.stripe.com/v1/charges'</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Authorization'</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${stripeSecret}</span>`</span> <span class="hljs-comment">// 💀 Anyone can charge!</span>
    },
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ amount })
  });
}

<span class="hljs-comment">// ✅ CORRECT - Secret on backend</span>
<span class="hljs-comment">// Frontend:</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Payment</span>(<span class="hljs-params">{ amount }</span>) </span>{
  <span class="hljs-comment">// ✨ No secrets! Only public API URL</span>
  fetch(<span class="hljs-string">'/api/create-charge'</span>, {  <span class="hljs-comment">// Your backend endpoint</span>
    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Authorization'</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${userToken}</span>`</span>  <span class="hljs-comment">// User's session token</span>
    },
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ amount })
  });
}

<span class="hljs-comment">// Backend (Node.js example):</span>
app.post(<span class="hljs-string">'/api/create-charge'</span>, authenticateUser, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-comment">// ✨ Secret stays on server, never sent to client!</span>
  <span class="hljs-keyword">const</span> stripe = <span class="hljs-built_in">require</span>(<span class="hljs-string">'stripe'</span>)(process.env.STRIPE_SECRET_KEY);

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> charge = <span class="hljs-keyword">await</span> stripe.charges.create({
      <span class="hljs-attr">amount</span>: req.body.amount,
      <span class="hljs-attr">currency</span>: <span class="hljs-string">'usd'</span>,
      <span class="hljs-attr">source</span>: req.body.token
    });

    res.json({ <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">chargeId</span>: charge.id });
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: error.message });
  }
});
</code></pre>
<pre><code class="lang-javascript">😱 Real Attack Example:

<span class="hljs-comment">// Your code:</span>
<span class="hljs-keyword">const</span> openaiKey = process.env.REACT_APP_OPENAI_KEY;

fetch(<span class="hljs-string">'https://api.openai.com/v1/chat/completions'</span>, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
  <span class="hljs-attr">headers</span>: {
    <span class="hljs-string">'Authorization'</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${openaiKey}</span>`</span>
  },
  <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
    <span class="hljs-attr">model</span>: <span class="hljs-string">'gpt-4'</span>,
    <span class="hljs-attr">messages</span>: [{ <span class="hljs-attr">role</span>: <span class="hljs-string">'user'</span>, <span class="hljs-attr">content</span>: userInput }]
  })
});

<span class="hljs-comment">// What happens:</span>
<span class="hljs-comment">// 1. Hacker opens your site</span>
<span class="hljs-comment">// 2. Checks main.js bundle</span>
<span class="hljs-comment">// 3. Finds: "sk-proj-abc123xyz..."</span>
<span class="hljs-comment">// 4. Copies key</span>
<span class="hljs-comment">// 5. Makes 10,000 GPT-4 requests</span>
<span class="hljs-comment">// 6. Your bill: $15,000! 💀</span>
<span class="hljs-comment">// 7. OpenAI suspends your account</span>
<span class="hljs-comment">// 8. Your app breaks</span>
<span class="hljs-comment">// 9. Company loses customers</span>

<span class="hljs-comment">// This happens DAILY to startups! 🚨</span>
</code></pre>
<pre><code class="lang-javascript">🔥 The Correct Pattern:

<span class="hljs-comment">// ✅ Frontend - No secrets</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ChatBot</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [message, setMessage] = useState(<span class="hljs-string">''</span>);
  <span class="hljs-keyword">const</span> [response, setResponse] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> sendMessage = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-comment">// ✨ Call YOUR backend, not OpenAI directly!</span>
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/chat'</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
        <span class="hljs-string">'Authorization'</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${getUserToken()}</span>`</span>  <span class="hljs-comment">// User's session</span>
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ message })
    });

    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> res.json();
    setResponse(data.reply);
  };

  <span class="hljs-keyword">return</span> (
    ....
  );
}

<span class="hljs-comment">// ✅ Backend - Secrets safe here</span>
app.post(<span class="hljs-string">'/api/chat'</span>, authenticateUser, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-comment">// ✨ Secret only exists on server!</span>
  <span class="hljs-keyword">const</span> openai = <span class="hljs-keyword">new</span> OpenAI({
    <span class="hljs-attr">apiKey</span>: process.env.OPENAI_API_KEY  <span class="hljs-comment">// Never sent to client!</span>
  });

  <span class="hljs-comment">// Rate limiting per user</span>
  <span class="hljs-keyword">const</span> userRequests = <span class="hljs-keyword">await</span> checkUserRateLimit(req.user.id);
  <span class="hljs-keyword">if</span> (userRequests &gt; <span class="hljs-number">100</span>) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">429</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">'Rate limit exceeded'</span> });
  }

  <span class="hljs-keyword">const</span> completion = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">'gpt-3.5-turbo'</span>,  <span class="hljs-comment">// Cheaper model for users</span>
    <span class="hljs-attr">messages</span>: [{ <span class="hljs-attr">role</span>: <span class="hljs-string">'user'</span>, <span class="hljs-attr">content</span>: req.body.message }],
    <span class="hljs-attr">max_tokens</span>: <span class="hljs-number">150</span>  <span class="hljs-comment">// Limit cost per request</span>
  });

  res.json({ <span class="hljs-attr">reply</span>: completion.choices[<span class="hljs-number">0</span>].message.content });
});
</code></pre>
<hr />
<h2 id="heading-6-react-object-mutation-trap-the-mutate-state-directly-silent-bug"><strong>6. React Object Mutation Trap: The "Mutate State Directly" Silent Bug</strong></h2>
<p>You mutate state objects/arrays directly and React doesn't re-render! Changes happen in memory but UI stays frozen.</p>
<p>Users see stale data, clicks don't work, forms don't update. This invisible mutation bug corrupts apps silently.</p>
<p><strong>The Problem:</strong></p>
<p>React detects changes by comparing references.</p>
<p>Mutate object in place = same reference = React thinks nothing changed = no re-render!</p>
<pre><code class="lang-javascript">❌ Direct Mutation (React Misses It):

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TodoList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [todos, setTodos] = useState([
    { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'Buy milk'</span>, <span class="hljs-attr">done</span>: <span class="hljs-literal">false</span> },
    { <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'Walk dog'</span>, <span class="hljs-attr">done</span>: <span class="hljs-literal">false</span> },
    { <span class="hljs-attr">id</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'Write code'</span>, <span class="hljs-attr">done</span>: <span class="hljs-literal">false</span> }
  ]);

  <span class="hljs-keyword">const</span> toggleTodo = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> todo = todos.find(<span class="hljs-function"><span class="hljs-params">t</span> =&gt;</span> t.id === id);
    <span class="hljs-comment">// 🚨 MUTATING the object directly!</span>
    todo.done = !todo.done;

    <span class="hljs-comment">// 🚨 Setting same array reference!</span>
    setTodos(todos);  <span class="hljs-comment">// 💀 React sees: old array === new array → no re-render!</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      {todos.map(todo =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{todo.id}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
            <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
            <span class="hljs-attr">checked</span>=<span class="hljs-string">{todo.done}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{()</span> =&gt;</span> toggleTodo(todo.id)}
          /&gt;
          {todo.text}
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
  );
}
</code></pre>
<pre><code class="lang-javascript">✅ Create New Reference (Immutable Update):

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TodoList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [todos, setTodos] = useState([
    { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'Buy milk'</span>, <span class="hljs-attr">done</span>: <span class="hljs-literal">false</span> },
    { <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'Walk dog'</span>, <span class="hljs-attr">done</span>: <span class="hljs-literal">false</span> },
    { <span class="hljs-attr">id</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'Write code'</span>, <span class="hljs-attr">done</span>: <span class="hljs-literal">false</span> }
  ]);

  <span class="hljs-keyword">const</span> toggleTodo = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> {
    <span class="hljs-comment">// ✨ Create NEW array with NEW objects!</span>
    setTodos(todos.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span>
      todo.id === id
        ? { ...todo, <span class="hljs-attr">done</span>: !todo.done }  <span class="hljs-comment">// ✨ New object!</span>
        : todo  <span class="hljs-comment">// Keep existing objects unchanged</span>
    ));
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
      {todos.map(todo =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{todo.id}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
            <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
            <span class="hljs-attr">checked</span>=<span class="hljs-string">{todo.done}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{()</span> =&gt;</span> toggleTodo(todo.id)}
          /&gt;
          {todo.text}
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Now:</span>
<span class="hljs-comment">// 1. User clicks checkbox for "Buy milk"</span>
<span class="hljs-comment">// 2. toggleTodo(1) called</span>
<span class="hljs-comment">// 3. ✨ .map creates NEW array</span>
<span class="hljs-comment">// 4. ✨ For id=1: { ...todo, done: !todo.done } creates NEW object</span>
<span class="hljs-comment">// 5. ✨ For id=2,3: returns existing objects (no change)</span>
<span class="hljs-comment">// 6. setTodos([newObj1, oldObj2, oldObj3])</span>
<span class="hljs-comment">// 7. ✅ React compares: oldArray !== newArray → TRUE!</span>
<span class="hljs-comment">// 8. ✅ React thinks: "Different reference, state changed!"</span>
<span class="hljs-comment">// 9. ✅ RE-RENDER triggered!</span>
<span class="hljs-comment">// 10. ✅ Checkbox updates on screen!</span>
<span class="hljs-comment">// 11. User happy! ✨</span>

<span class="hljs-comment">// React's comparison:</span>
<span class="hljs-comment">// prevState !== nextState → Re-render! ✅</span>
<span class="hljs-comment">// [1,2,3] !== [1,2,3]  // Different array objects!</span>
</code></pre>
<pre><code class="lang-javascript">🔥 Real Mutation Bugs:

Bug <span class="hljs-number">1</span>: Nested <span class="hljs-built_in">Object</span> Mutation

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserSettings</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [user, setUser] = useState({
    <span class="hljs-attr">name</span>: <span class="hljs-string">'John'</span>,
    <span class="hljs-attr">settings</span>: {
      <span class="hljs-attr">theme</span>: <span class="hljs-string">'light'</span>,
      <span class="hljs-attr">notifications</span>: {
        <span class="hljs-attr">email</span>: <span class="hljs-literal">true</span>,
        <span class="hljs-attr">push</span>: <span class="hljs-literal">false</span>
      }
    }
  });

  <span class="hljs-keyword">const</span> toggleEmail = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// 🚨 DEEP mutation!</span>
    user.settings.notifications.email = !user.settings.notifications.email;
    setUser(user);  <span class="hljs-comment">// 💀 Same reference!</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
          <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span>
          <span class="hljs-attr">checked</span>=<span class="hljs-string">{user.settings.notifications.email}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{toggleEmail}</span>
        /&gt;</span>
        Email Notifications
      <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Bug:</span>
<span class="hljs-comment">// 1. User clicks checkbox</span>
<span class="hljs-comment">// 2. toggleEmail() called</span>
<span class="hljs-comment">// 3. 💀 Mutates deep nested property</span>
<span class="hljs-comment">// 4. setUser(user) - same object reference</span>
<span class="hljs-comment">// 5. 💀 React doesn't re-render!</span>
<span class="hljs-comment">// 6. Checkbox doesn't update</span>
<span class="hljs-comment">// 7. User clicks 5 more times</span>
<span class="hljs-comment">// 8. 💀 Still no visual change!</span>
<span class="hljs-comment">// 9. Data in memory: true → false → true → false...</span>
<span class="hljs-comment">// 10. UI shows: true (frozen) 💀</span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// ✅ Fix: Immutable deep update</span>
<span class="hljs-keyword">const</span> toggleEmail = <span class="hljs-function">() =&gt;</span> {
  setUser({
    ...user,  <span class="hljs-comment">// ✨ Copy top level</span>
    <span class="hljs-attr">settings</span>: {
      ...user.settings,  <span class="hljs-comment">// ✨ Copy second level</span>
      <span class="hljs-attr">notifications</span>: {
        ...user.settings.notifications,  <span class="hljs-comment">// ✨ Copy third level</span>
        <span class="hljs-attr">email</span>: !user.settings.notifications.email  <span class="hljs-comment">// ✨ Change value</span>
      }
    }
  });
};

<span class="hljs-comment">// Or use immer for easier deep updates:</span>
<span class="hljs-keyword">import</span> { produce } <span class="hljs-keyword">from</span> <span class="hljs-string">'immer'</span>;

<span class="hljs-keyword">const</span> toggleEmail = <span class="hljs-function">() =&gt;</span> {
  setUser(produce(<span class="hljs-function"><span class="hljs-params">draft</span> =&gt;</span> {
    draft.settings.notifications.email = !draft.settings.notifications.email;
    <span class="hljs-comment">// ✨ Immer creates new object behind the scenes!</span>
  }));
};
</code></pre>
<pre><code class="lang-javascript">Bug <span class="hljs-number">2</span>: <span class="hljs-built_in">Array</span> Push/Splice Mutation

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ShoppingCart</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [items, setItems] = useState([]);

  <span class="hljs-keyword">const</span> addItem = <span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> {
    <span class="hljs-comment">// 🚨 MUTATING array!</span>
    items.push(product);  <span class="hljs-comment">// 💀 Modifies original array!</span>
    setItems(items);  <span class="hljs-comment">// 💀 Same reference!</span>
  };

  <span class="hljs-keyword">const</span> removeItem = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
    <span class="hljs-comment">// 🚨 MUTATING array!</span>
    items.splice(index, <span class="hljs-number">1</span>);  <span class="hljs-comment">// 💀 Modifies original array!</span>
    setItems(items);  <span class="hljs-comment">// 💀 Same reference!</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Cart: {items.length} items<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      {items.map((item, index) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>
          {item.name} - ${item.price}
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> removeItem(index)}&gt;Remove<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      ))}
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> addItem({ name: 'Widget', price: 10 })}&gt;
        Add Widget
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Bug:</span>
<span class="hljs-comment">// 1. User clicks "Add Widget"</span>
<span class="hljs-comment">// 2. addItem() called</span>
<span class="hljs-comment">// 3. items.push() mutates array: [] → [widget]</span>
<span class="hljs-comment">// 4. setItems(items) - same array reference</span>
<span class="hljs-comment">// 5. 💀 React doesn't re-render!</span>
<span class="hljs-comment">// 6. UI still shows: "Cart: 0 items" 💀</span>
<span class="hljs-comment">// 7. User clicks "Add" 5 more times</span>
<span class="hljs-comment">// 8. Array in memory: [w, w, w, w, w, w]</span>
<span class="hljs-comment">// 9. UI still shows: "Cart: 0 items" 💀</span>
<span class="hljs-comment">// 10. User refreshes page</span>
<span class="hljs-comment">// 11. Cart data lost (wasn't persisted)</span>
<span class="hljs-comment">// 12. User: "I added 6 items! Where are they?!" 😡</span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// ✅ Fix: Immutable operations</span>
<span class="hljs-keyword">const</span> addItem = <span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> {
  setItems([...items, product]);  <span class="hljs-comment">// ✨ New array!</span>
};

<span class="hljs-keyword">const</span> removeItem = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
  setItems(items.filter(<span class="hljs-function">(<span class="hljs-params">_, i</span>) =&gt;</span> i !== index));  <span class="hljs-comment">// ✨ New array!</span>
};

<span class="hljs-comment">// Or:</span>
<span class="hljs-keyword">const</span> addItem = <span class="hljs-function">(<span class="hljs-params">product</span>) =&gt;</span> {
  setItems(<span class="hljs-function"><span class="hljs-params">prevItems</span> =&gt;</span> [...prevItems, product]);
};

<span class="hljs-keyword">const</span> removeItem = <span class="hljs-function">(<span class="hljs-params">index</span>) =&gt;</span> {
  setItems(<span class="hljs-function"><span class="hljs-params">prevItems</span> =&gt;</span> prevItems.filter(<span class="hljs-function">(<span class="hljs-params">_, i</span>) =&gt;</span> i !== index));
};
</code></pre>
<pre><code class="lang-javascript">Bug <span class="hljs-number">3</span>: Sort Mutation

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductList</span>(<span class="hljs-params">{ products }</span>) </span>{
  <span class="hljs-keyword">const</span> [sortedProducts, setSortedProducts] = useState(products);
  <span class="hljs-keyword">const</span> [sortOrder, setSortOrder] = useState(<span class="hljs-string">'asc'</span>);

  <span class="hljs-keyword">const</span> handleSort = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// 🚨 MUTATING array!</span>
    sortedProducts.sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> sortOrder === <span class="hljs-string">'asc'</span> 
        ? a.price - b.price 
        : b.price - a.price;
    });

    setSortedProducts(sortedProducts);  <span class="hljs-comment">// 💀 Same reference!</span>
    setSortOrder(sortOrder === <span class="hljs-string">'asc'</span> ? <span class="hljs-string">'desc'</span> : <span class="hljs-string">'asc'</span>);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSort}</span>&gt;</span>
        Sort by Price ({sortOrder})
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      {sortedProducts.map(product =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{product.id}</span>&gt;</span>
          {product.name} - ${product.price}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Bug:</span>
<span class="hljs-comment">// 1. User clicks "Sort by Price (asc)"</span>
<span class="hljs-comment">// 2. handleSort() called</span>
<span class="hljs-comment">// 3. sortedProducts.sort() mutates array in place</span>
<span class="hljs-comment">// 4. setSortedProducts(sortedProducts) - same reference</span>
<span class="hljs-comment">// 5. 💀 React doesn't re-render sortedProducts!</span>
<span class="hljs-comment">// 6. setSortOrder('desc') triggers re-render</span>
<span class="hljs-comment">// 7. ✅ Button text updates: "(desc)"</span>
<span class="hljs-comment">// 8. 💀 But product list DOESN'T re-sort!</span>
<span class="hljs-comment">// 9. User sees: Button says "desc" but list is still "asc" order</span>
<span class="hljs-comment">// 10. Clicks again</span>
<span class="hljs-comment">// 11. 💀 Still no visual change to list!</span>
<span class="hljs-comment">// 12. UI state inconsistent! 💀</span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// ✅ Fix: Create new sorted array</span>
<span class="hljs-keyword">const</span> handleSort = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> newOrder = sortOrder === <span class="hljs-string">'asc'</span> ? <span class="hljs-string">'desc'</span> : <span class="hljs-string">'asc'</span>;

  <span class="hljs-keyword">const</span> sorted = [...sortedProducts].sort(<span class="hljs-function">(<span class="hljs-params">a, b</span>) =&gt;</span> {  <span class="hljs-comment">// ✨ Copy first!</span>
    <span class="hljs-keyword">return</span> newOrder === <span class="hljs-string">'asc'</span> 
      ? a.price - b.price 
      : b.price - a.price;
  });

  setSortedProducts(sorted);  <span class="hljs-comment">// ✨ New array!</span>
  setSortOrder(newOrder);
};
</code></pre>
<pre><code class="lang-javascript">💪 Mutation Methods to AVOID:

<span class="hljs-comment">// ❌ Array mutations (modify original)</span>
array.push(item)           <span class="hljs-comment">// Use: [...array, item]</span>
array.pop()                <span class="hljs-comment">// Use: array.slice(0, -1)</span>
array.shift()              <span class="hljs-comment">// Use: array.slice(1)</span>
array.unshift(item)        <span class="hljs-comment">// Use: [item, ...array]</span>
array.splice(i, <span class="hljs-number">1</span>)         <span class="hljs-comment">// Use: array.filter((_, index) =&gt; index !== i)</span>
array.sort()               <span class="hljs-comment">// Use: [...array].sort()</span>
array.reverse()            <span class="hljs-comment">// Use: [...array].reverse()</span>
array[i] = value           <span class="hljs-comment">// Use: array.map((item, index) =&gt; index === i ? value : item)</span>

<span class="hljs-comment">// ❌ Object mutations (modify original)</span>
object.property = value    <span class="hljs-comment">// Use: { ...object, property: value }</span>
<span class="hljs-keyword">delete</span> object.property     <span class="hljs-comment">// Use: const { property, ...rest } = object; return rest;</span>
<span class="hljs-built_in">Object</span>.assign(object, {})  <span class="hljs-comment">// Use: { ...object, ...newProps }</span>

<span class="hljs-comment">// ✅ Immutable alternatives</span>
<span class="hljs-comment">// Arrays:</span>
[...array, newItem]                    <span class="hljs-comment">// Add to end</span>
[newItem, ...array]                    <span class="hljs-comment">// Add to start</span>
array.filter(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.id !== id)   <span class="hljs-comment">// Remove</span>
array.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.id === id ? newItem : item)  <span class="hljs-comment">// Update</span>
[...array].sort()                      <span class="hljs-comment">// Sort</span>
array.slice(<span class="hljs-number">0</span>, index).concat(array.slice(index + <span class="hljs-number">1</span>))  <span class="hljs-comment">// Remove at index</span>

<span class="hljs-comment">// Objects:</span>
{ ...object, <span class="hljs-attr">key</span>: newValue }           <span class="hljs-comment">// Update property</span>
{ ...object, <span class="hljs-attr">nested</span>: { ...object.nested, <span class="hljs-attr">key</span>: value } }  <span class="hljs-comment">// Deep update</span>
<span class="hljs-keyword">const</span> { removeThis, ...keep } = object; keep;  <span class="hljs-comment">// Remove property</span>
</code></pre>
<pre><code class="lang-javascript">📊 Mutation Detection:

<span class="hljs-comment">// React's state comparison:</span>

<span class="hljs-comment">// Primitives (compared by value):</span>
<span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);
setCount(<span class="hljs-number">0</span>);  <span class="hljs-comment">// 0 === 0 → No re-render ✅</span>
setCount(<span class="hljs-number">1</span>);  <span class="hljs-comment">// 0 !== 1 → Re-render ✅</span>

<span class="hljs-comment">// Objects/Arrays (compared by reference):</span>
<span class="hljs-keyword">const</span> [obj, setObj] = useState({ <span class="hljs-attr">a</span>: <span class="hljs-number">1</span> });

<span class="hljs-comment">// ❌ Mutation (same reference):</span>
obj.a = <span class="hljs-number">2</span>;
setObj(obj);  <span class="hljs-comment">// obj === obj → No re-render 💀</span>

<span class="hljs-comment">// ✅ New object (different reference):</span>
setObj({ ...obj, <span class="hljs-attr">a</span>: <span class="hljs-number">2</span> });  <span class="hljs-comment">// oldObj !== newObj → Re-render ✅</span>

<span class="hljs-comment">// Why mutation fails:</span>
<span class="hljs-keyword">const</span> array1 = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];
array1.push(<span class="hljs-number">4</span>);  <span class="hljs-comment">// Mutates array1</span>
array1 === array1  <span class="hljs-comment">// Still TRUE! Same reference!</span>

<span class="hljs-keyword">const</span> array2 = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>];
<span class="hljs-keyword">const</span> array3 = [...array2, <span class="hljs-number">4</span>];  <span class="hljs-comment">// New array</span>
array2 === array3  <span class="hljs-comment">// FALSE! Different references!</span>

<span class="hljs-comment">// React uses Object.is() for comparison:</span>
<span class="hljs-built_in">Object</span>.is(oldState, newState)
<span class="hljs-comment">// If TRUE → Skip re-render</span>
<span class="hljs-comment">// If FALSE → Trigger re-render</span>
</code></pre>
<pre><code class="lang-javascript">✨ Immutable Update Patterns:

<span class="hljs-comment">// Pattern 1: Array - Add item</span>
setArray([...array, newItem]);
setArray(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> [...prev, newItem]);

<span class="hljs-comment">// Pattern 2: Array - Remove item</span>
setArray(array.filter(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.id !== id));
setArray(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> prev.filter(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item.id !== id));

<span class="hljs-comment">// Pattern 3: Array - Update item</span>
setArray(array.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> 
  item.id === id ? { ...item, <span class="hljs-attr">name</span>: <span class="hljs-string">'New'</span> } : item
));

<span class="hljs-comment">// Pattern 4: Array - Replace at index</span>
setArray(array.map(<span class="hljs-function">(<span class="hljs-params">item, i</span>) =&gt;</span> 
  i === index ? newItem : item
));

<span class="hljs-comment">// Pattern 5: Object - Update property</span>
setObject({ ...object, <span class="hljs-attr">key</span>: value });
setObject(<span class="hljs-function"><span class="hljs-params">prev</span> =&gt;</span> ({ ...prev, <span class="hljs-attr">key</span>: value }));

<span class="hljs-comment">// Pattern 6: Object - Update nested</span>
setObject({
  ...object,
  <span class="hljs-attr">nested</span>: {
    ...object.nested,
    <span class="hljs-attr">deepKey</span>: value
  }
});

<span class="hljs-comment">// Pattern 7: Object - Remove property</span>
<span class="hljs-keyword">const</span> { removeKey, ...rest } = object;
setObject(rest);

<span class="hljs-comment">// Pattern 8: Object - Merge</span>
setObject({ ...object, ...updates });

<span class="hljs-comment">// Pattern 9: Array of objects - Update one</span>
setArray(array.map(<span class="hljs-function"><span class="hljs-params">obj</span> =&gt;</span>
  obj.id === id ? { ...obj, <span class="hljs-attr">done</span>: !obj.done } : obj
));

<span class="hljs-comment">// Pattern 10: Complex nested update (use immer)</span>
<span class="hljs-keyword">import</span> { produce } <span class="hljs-keyword">from</span> <span class="hljs-string">'immer'</span>;

setData(produce(<span class="hljs-function"><span class="hljs-params">draft</span> =&gt;</span> {
  draft.users[<span class="hljs-number">0</span>].profile.settings.theme = <span class="hljs-string">'dark'</span>;
  <span class="hljs-comment">// ✨ Immer handles immutability!</span>
}));
</code></pre>
<hr />
<h2 id="heading-7-react-accessibility-trap-the-div-onclick-keyboard-trap"><strong>7. React Accessibility Trap: The "div onClick" Keyboard Trap</strong></h2>
<p>Your clickable divs are INVISIBLE to keyboard users! 15% of users can't use your app because you used onClick on div instead of button.</p>
<p>This is a lawsuit waiting to happen. This pattern destroys production performance.</p>
<p><strong>The Problem:</strong></p>
<p>Divs aren't keyboard accessible. Screen readers skip them. Tab key ignores them. You just blocked millions of users!</p>
<pre><code class="lang-javascript">❌ The Accessibility Disaster:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductCard</span>(<span class="hljs-params">{ product, onAddToCart }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"product-card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.name}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>${product.price}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

      {/* 🚨 ACCESSIBILITY NIGHTMARE! */}
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> 
        <span class="hljs-attr">className</span>=<span class="hljs-string">"add-to-cart-button"</span>
        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> onAddToCart(product.id)}
      &gt;
        Add to Cart
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// What happens for keyboard users:</span>
<span class="hljs-comment">// 1. User presses Tab key</span>
<span class="hljs-comment">// 2. ❌ Focus skips the "button" (it's a div!)</span>
<span class="hljs-comment">// 3. User can't reach "Add to Cart"</span>
<span class="hljs-comment">// 4. User can't buy product</span>
<span class="hljs-comment">// 5. You lost a customer! 💀</span>

<span class="hljs-comment">// What happens for screen reader users:</span>
<span class="hljs-comment">// 1. Screen reader reads page</span>
<span class="hljs-comment">// 2. ❌ Announces "Add to Cart" as text, not a button</span>
<span class="hljs-comment">// 3. User doesn't know it's clickable</span>
<span class="hljs-comment">// 4. No way to activate it with voice commands</span>
<span class="hljs-comment">// 5. User leaves frustrated! 😡</span>

<span class="hljs-comment">// What happens legally:</span>
<span class="hljs-comment">// 1. User files ADA complaint</span>
<span class="hljs-comment">// 2. Company faces lawsuit</span>
<span class="hljs-comment">// 3. Settlement: $50,000-$500,000</span>
<span class="hljs-comment">// 4. Mandatory accessibility audit: $30,000</span>
<span class="hljs-comment">// 5. Remediation work: $100,000+</span>
<span class="hljs-comment">// Total cost: $180,000+ for using &lt;div&gt; instead of &lt;button&gt;! 💀</span>
</code></pre>
<pre><code class="lang-javascript">✅ Accessible Button (Correct):

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductCard</span>(<span class="hljs-params">{ product, onAddToCart }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"product-card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.name}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>${product.price}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

      {/* ✨ ACCESSIBLE! */}
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> 
        <span class="hljs-attr">className</span>=<span class="hljs-string">"add-to-cart-button"</span>
        <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> onAddToCart(product.id)}
      &gt;
        Add to Cart
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// What happens now:</span>
<span class="hljs-comment">// Keyboard users:</span>
<span class="hljs-comment">// 1. Tab key focuses the button</span>
<span class="hljs-comment">// 2. Enter/Space activates it</span>
<span class="hljs-comment">// 3. Can add to cart!</span>

<span class="hljs-comment">// Screen reader users:</span>
<span class="hljs-comment">// 1. Announces "Add to Cart, button"</span>
<span class="hljs-comment">// 2. User knows it's interactive</span>
<span class="hljs-comment">// 3. Voice commands work: "Click Add to Cart button"</span>
<span class="hljs-comment">// 4. Can buy product!</span>

<span class="hljs-comment">// Legal compliance:</span>
<span class="hljs-comment">// ✅ WCAG 2.1 compliant</span>
<span class="hljs-comment">// ✅ ADA compliant</span>
<span class="hljs-comment">// ✅ Section 508 compliant</span>
<span class="hljs-comment">// ✅ No lawsuits!</span>
</code></pre>
<pre><code class="lang-javascript">🔥 Real Accessibility Issues:

Issue <span class="hljs-number">1</span>: Modal Close Button

<span class="hljs-comment">// ❌ BAD - Keyboard trap!</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Modal</span>(<span class="hljs-params">{ isOpen, onClose, children }</span>) </span>{
  <span class="hljs-keyword">if</span> (!isOpen) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-overlay"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClose}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal"</span>&gt;</span>
        {/* 🚨 Not keyboard accessible! */}
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"close-button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClose}</span>&gt;</span>
          ×
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {children}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Keyboard user:</span>
<span class="hljs-comment">// 1. Opens modal</span>
<span class="hljs-comment">// 2. Presses Tab to close</span>
<span class="hljs-comment">// 3. ❌ Can't focus on × button</span>
<span class="hljs-comment">// 4. Presses Esc key</span>
<span class="hljs-comment">// 5. ❌ Nothing happens (no keyboard handler!)</span>
<span class="hljs-comment">// 6. 💀 TRAPPED IN MODAL FOREVER!</span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// ✅ GOOD - Fully accessible</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Modal</span>(<span class="hljs-params">{ isOpen, onClose, children }</span>) </span>{
  <span class="hljs-keyword">if</span> (!isOpen) <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;

  <span class="hljs-comment">// ✨ Close on Escape key</span>
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> handleEscape = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (e.key === <span class="hljs-string">'Escape'</span>) onClose();
    };

    <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">'keydown'</span>, handleEscape);
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">document</span>.removeEventListener(<span class="hljs-string">'keydown'</span>, handleEscape);
  }, [onClose]);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> 
      <span class="hljs-attr">className</span>=<span class="hljs-string">"modal-overlay"</span> 
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClose}</span>
      <span class="hljs-attr">role</span>=<span class="hljs-string">"dialog"</span>  // ✨ <span class="hljs-attr">Semantic</span> <span class="hljs-attr">role</span>
      <span class="hljs-attr">aria-modal</span>=<span class="hljs-string">"true"</span>  // ✨ <span class="hljs-attr">Tells</span> <span class="hljs-attr">screen</span> <span class="hljs-attr">readers</span> <span class="hljs-attr">it</span>'<span class="hljs-attr">s</span> <span class="hljs-attr">a</span> <span class="hljs-attr">modal</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"modal"</span>&gt;</span>
        {/* ✨ Real button! */}
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> 
          <span class="hljs-attr">className</span>=<span class="hljs-string">"close-button"</span> 
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{onClose}</span>
          <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Close modal"</span>  // ✨ <span class="hljs-attr">Screen</span> <span class="hljs-attr">reader</span> <span class="hljs-attr">text</span>
        &gt;</span>
          ×
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        {children}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Now:</span>
<span class="hljs-comment">// 1. Tab focuses close button</span>
<span class="hljs-comment">// 2. Enter/Space closes modal</span>
<span class="hljs-comment">// 3. Escape key closes modal</span>
<span class="hljs-comment">// 4. Screen reader announces "Close modal, button"</span>
<span class="hljs-comment">// 5. No one trapped!</span>
</code></pre>
<pre><code class="lang-javascript">Issue <span class="hljs-number">2</span>: Card Click

<span class="hljs-comment">// ❌ BAD - Entire card clickable with div</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductCard</span>(<span class="hljs-params">{ product }</span>) </span>{
  <span class="hljs-keyword">const</span> navigate = useNavigate();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> 
      <span class="hljs-attr">className</span>=<span class="hljs-string">"product-card"</span>
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> navigate(`/products/${product.id}`)}
      style={{ cursor: 'pointer' }}  // 🚨 Looks clickable, but...
    &gt;
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.name}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>${product.price}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Problems:</span>
<span class="hljs-comment">// ❌ Can't Tab to card</span>
<span class="hljs-comment">// ❌ Can't activate with keyboard</span>
<span class="hljs-comment">// ❌ Screen reader doesn't know it's clickable</span>
<span class="hljs-comment">// ❌ Can't use with voice commands</span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">// ✅ GOOD - Semantic link</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductCard</span>(<span class="hljs-params">{ product }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"product-card"</span>&gt;</span>
      {/* ✨ Wrap in link for navigation */}
      <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> 
        <span class="hljs-attr">to</span>=<span class="hljs-string">{</span>`/<span class="hljs-attr">products</span>/${<span class="hljs-attr">product.id</span>}`}
        <span class="hljs-attr">className</span>=<span class="hljs-string">"product-link"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.name}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>${product.price}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Or if it's an action, not navigation:</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductCard</span>(<span class="hljs-params">{ product, onQuickView }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"product-card"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{product.image}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{product.name}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>${product.price}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

      {/* ✨ Button for action */}
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> onQuickView(product)}&gt;
        Quick View
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Now:</span>
<span class="hljs-comment">// 1. Tab to focus</span>
<span class="hljs-comment">// 2. Enter to activate</span>
<span class="hljs-comment">// 3. Screen reader: "Link, {product.name}" or "Button, Quick View"</span>
<span class="hljs-comment">// 4. Voice commands work</span>
</code></pre>
<pre><code class="lang-javascript">💪 The Keyboard Navigation Rules:

<span class="hljs-comment">// Rule 1: Navigation = &lt;Link&gt; or &lt;a&gt;</span>
<span class="hljs-comment">// ✅ CORRECT</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/dashboard"</span>&gt;</span>Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/dashboard"</span>&gt;</span>Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></span>

<span class="hljs-comment">// ❌ WRONG</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> navigate('/dashboard')}&gt;Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>

<span class="hljs-comment">// Rule 2: Actions = &lt;button&gt;</span>
<span class="hljs-comment">// ✅ CORRECT</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleDelete}</span>&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>

<span class="hljs-comment">// ❌ WRONG</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleDelete}</span>&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>

<span class="hljs-comment">// Rule 3: If it looks clickable, make it focusable</span>
<span class="hljs-comment">// ✅ CORRECT</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"icon-button"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">Icon</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"trash"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>

<span class="hljs-comment">// ❌ WRONG</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"icon-button"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">Icon</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"trash"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>

<span class="hljs-comment">// Rule 4: Custom interactive elements need tabIndex and role</span>
<span class="hljs-comment">// ✅ ONLY if you absolutely can't use button/link</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
  <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span>
  <span class="hljs-attr">tabIndex</span>=<span class="hljs-string">{0}</span>
  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>
  <span class="hljs-attr">onKeyDown</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      handleClick();
    }
  }}
&gt;
  Custom Button
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>

<span class="hljs-comment">// But seriously, just use &lt;button&gt;! ✨</span>
</code></pre>
<pre><code class="lang-javascript">📊 Accessibility Impact:

Your e-commerce site <span class="hljs-keyword">with</span> div buttons:

Users affected:
├─ Keyboard-only users: <span class="hljs-number">5</span><span class="hljs-number">-10</span>% <span class="hljs-keyword">of</span> all users
├─ Screen reader users: <span class="hljs-number">1</span><span class="hljs-number">-2</span>%
├─ Voice control users: <span class="hljs-number">2</span><span class="hljs-number">-3</span>%
├─ Motor disability users: <span class="hljs-number">3</span><span class="hljs-number">-5</span>%
├─ Temporary disability (broken mouse): <span class="hljs-number">5</span>%
└─ Total: <span class="hljs-number">15</span><span class="hljs-number">-20</span>% <span class="hljs-keyword">of</span> potential customers! 💀

If you have <span class="hljs-number">100</span>,<span class="hljs-number">000</span> monthly visitors:
├─ <span class="hljs-number">15</span>,<span class="hljs-number">000</span><span class="hljs-number">-20</span>,<span class="hljs-number">000</span> can<span class="hljs-string">'t use your site
├─ Average order value: $50
├─ Conversion rate: 2%
├─ Lost revenue: $15,000-$20,000/month
└─ Annual: $180,000-$240,000 lost! 💸

Plus legal risk:
├─ ADA lawsuit settlements: $50K-$500K
├─ Remediation costs: $50K-$200K
└─ Reputation damage: Priceless 💀

Fix: Replace &lt;div onClick&gt; with &lt;button&gt;
Cost: 5 minutes
Savings: Hundreds of thousands of dollars!</span>
</code></pre>
<pre><code class="lang-javascript">🔥 ESLint Rules:

<span class="hljs-comment">// .eslintrc.js</span>
{
  <span class="hljs-string">"plugins"</span>: [<span class="hljs-string">"jsx-a11y"</span>],
  <span class="hljs-string">"rules"</span>: {
    <span class="hljs-comment">// ✨ Catches clickable divs!</span>
    <span class="hljs-string">"jsx-a11y/no-static-element-interactions"</span>: <span class="hljs-string">"error"</span>,
    <span class="hljs-string">"jsx-a11y/click-events-have-key-events"</span>: <span class="hljs-string">"error"</span>,
    <span class="hljs-string">"jsx-a11y/no-noninteractive-element-interactions"</span>: <span class="hljs-string">"error"</span>,

    <span class="hljs-comment">// ✨ Enforces proper roles</span>
    <span class="hljs-string">"jsx-a11y/role-has-required-aria-props"</span>: <span class="hljs-string">"error"</span>,

    <span class="hljs-comment">// ✨ Requires alt text on images</span>
    <span class="hljs-string">"jsx-a11y/alt-text"</span>: <span class="hljs-string">"error"</span>
  }
}

<span class="hljs-comment">// Install:</span>
npm install --save-dev eslint-plugin-jsx-a11y

<span class="hljs-comment">// Now ESLint will catch:</span>
&lt;div onClick={handleClick}&gt;  <span class="hljs-comment">// ❌ Error!</span>
<span class="hljs-comment">// ⚠️ Visible, non-interactive elements with click handlers</span>
<span class="hljs-comment">//    must have at least one keyboard listener</span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>  // ✅ No error!</span>
</code></pre>
<pre><code class="lang-javascript">💡 Testing Accessibility:

Manual test (takes <span class="hljs-number">2</span> minutes):
<span class="hljs-number">1.</span> Unplug your mouse
<span class="hljs-number">2.</span> Use only Tab key to navigate
<span class="hljs-number">3.</span> Can you reach every interactive element?
<span class="hljs-number">4.</span> Can you activate them <span class="hljs-keyword">with</span> Enter/Space?

If NO to any → You have accessibility issues!

Automated tools:
├─ axe DevTools (Chrome extension)
├─ Lighthouse (Chrome DevTools)
├─ WAVE (Browser extension)
└─ React axe (<span class="hljs-keyword">in</span> development)

Screen reader test:
├─ Mac: Turn on VoiceOver (Cmd+F5)
├─ Windows: Turn on Narrator (Ctrl+Win+Enter)
├─ Navigate your site
└─ Do interactive elements announce correctly?

🎯 The Checklist:

For every interactive element:

☑️ Can you Tab to it?
☑️ Can you activate <span class="hljs-keyword">with</span> Enter/Space?
☑️ Does screen reader announce it correctly?
☑️ Does it have visible focus indicator?
☑️ Can you use it without a mouse?

If NO to any:
✅ Use &lt;button&gt; <span class="hljs-keyword">for</span> actions
✅ Use &lt;a&gt; or &lt;Link&gt; <span class="hljs-keyword">for</span> navigation
✅ Add proper ARIA labels
✅ Add keyboard event handlers
✅ Test <span class="hljs-keyword">with</span> keyboard only
</code></pre>
<pre><code class="lang-javascript">🚨 Legal Reality:

Recent accessibility lawsuits:

Domino<span class="hljs-string">'s Pizza: $4,000 + legal fees + remediation
Winn-Dixie: $100,000 settlement
Target: $6 million settlement
Bank of America: $3.5 million

Common violation: Clickable divs without keyboard access

Your risk:
├─ Anyone can file ADA complaint
├─ No warning required
├─ Settlements average $50K-$500K
└─ Plus your legal fees and remediation

Prevention cost: Use &lt;button&gt; instead of &lt;div onClick&gt;
Literally free! Just better HTML! ✨</span>
</code></pre>
<hr />
<h2 id="heading-8-react-async-trap-the-promise-race-condition-bug-that-corrupts-data"><strong>8. React Async Trap: The "Promise Race Condition" Bug That Corrupts Data</strong></h2>
<p>Your async code shows wrong data and you have NO IDEA why! Fast clicks create race conditions that display stale responses. This bug is invisible until production.</p>
<p><strong>The Problem:</strong></p>
<p>Multiple async requests racing - the last one to START wins, but the last one to FINISH displays!</p>
<pre><code class="lang-javascript">❌ The Race Condition:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserProfile</span>(<span class="hljs-params">{ userId }</span>) </span>{
  <span class="hljs-keyword">const</span> [user, setUser] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// 🚨 No cleanup! Race condition waiting to happen!</span>
    fetchUser(userId).then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
      setUser(data);
    });
  }, [userId]);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{user?.name}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

<span class="hljs-comment">// Bug scenario:</span>
<span class="hljs-comment">// 1. User clicks Profile #1 (slow server, takes 3 seconds)</span>
<span class="hljs-comment">// 2. User quickly clicks Profile #2 (fast server, takes 0.5 seconds)</span>
<span class="hljs-comment">// 3. Profile #2 loads: ✅ Shows User #2 (correct)</span>
<span class="hljs-comment">// 4. Profile #1 finishes: 😱 Shows User #1 (WRONG!)</span>
<span class="hljs-comment">// 5. URL says "profile/2" but shows User #1 data!</span>
<span class="hljs-comment">// Data corruption! User confused! 💀</span>

<span class="hljs-comment">// Timeline:</span>
<span class="hljs-comment">// 0.0s: Request User #1 (start)</span>
<span class="hljs-comment">// 0.1s: Request User #2 (start)  ← Should cancel #1!</span>
<span class="hljs-comment">// 0.6s: User #2 arrives, setUser(#2)  ✅</span>
<span class="hljs-comment">// 3.0s: User #1 arrives, setUser(#1)  😱 OVERWRITES!</span>
<span class="hljs-comment">// Result: Shows User #1 in User #2's profile!</span>
</code></pre>
<pre><code class="lang-javascript">✅ Fix #<span class="hljs-number">1</span> - Abort Controller:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserProfile</span>(<span class="hljs-params">{ userId }</span>) </span>{
  <span class="hljs-keyword">const</span> [user, setUser] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// ✨ Create abort controller</span>
    <span class="hljs-keyword">const</span> controller = <span class="hljs-keyword">new</span> AbortController();

    fetchUser(userId, { <span class="hljs-attr">signal</span>: controller.signal })
      .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
        setUser(data);
      })
      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
        <span class="hljs-keyword">if</span> (error.name !== <span class="hljs-string">'AbortError'</span>) {
          <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Fetch error:'</span>, error);
        }
        <span class="hljs-comment">// AbortError is expected when switching users</span>
      });

    <span class="hljs-comment">// ✨ Cleanup: Cancel previous request!</span>
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      controller.abort();
    };
  }, [userId]);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{user?.name}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

<span class="hljs-comment">// Now:</span>
<span class="hljs-comment">// 1. Request User #1 starts</span>
<span class="hljs-comment">// 2. User clicks User #2</span>
<span class="hljs-comment">// 3. ✨ useEffect cleanup runs → abort Request #1</span>
<span class="hljs-comment">// 4. Request #2 starts</span>
<span class="hljs-comment">// 5. Only User #2 data displays!</span>
<span class="hljs-comment">// No race condition! ✨</span>
</code></pre>
<pre><code class="lang-javascript">✅ Fix #<span class="hljs-number">2</span> - Ignore Stale Responses:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserProfile</span>(<span class="hljs-params">{ userId }</span>) </span>{
  <span class="hljs-keyword">const</span> [user, setUser] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">let</span> isCurrent = <span class="hljs-literal">true</span>;  <span class="hljs-comment">// ✨ Track if this effect is still relevant</span>

    fetchUser(userId).then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
      <span class="hljs-comment">// ✨ Only update if this is still the current userId</span>
      <span class="hljs-keyword">if</span> (isCurrent) {
        setUser(data);
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Ignoring stale response for userId:'</span>, userId);
      }
    });

    <span class="hljs-comment">// ✨ Cleanup: Mark as stale</span>
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      isCurrent = <span class="hljs-literal">false</span>;
    };
  }, [userId]);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{user?.name}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

<span class="hljs-comment">// Now:</span>
<span class="hljs-comment">// 1. Request User #1, isCurrent = true</span>
<span class="hljs-comment">// 2. User clicks User #2</span>
<span class="hljs-comment">// 3. ✨ Cleanup runs: isCurrent (for #1) = false</span>
<span class="hljs-comment">// 4. Request User #2, new isCurrent = true</span>
<span class="hljs-comment">// 5. User #2 arrives: isCurrent = true → setUser ✅</span>
<span class="hljs-comment">// 6. User #1 arrives late: isCurrent = false → ignored! ✨</span>
</code></pre>
<pre><code class="lang-javascript">🔥 Real Bug Examples:

Bug <span class="hljs-number">1</span>: Search Results

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SearchResults</span>(<span class="hljs-params">{ query }</span>) </span>{
  <span class="hljs-keyword">const</span> [results, setResults] = useState([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// 🚨 Race condition!</span>
    searchAPI(query).then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
      setResults(data);
    });
  }, [query]);

  <span class="hljs-keyword">return</span> results.map(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Result</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{r.id}</span> {<span class="hljs-attr">...r</span>} /&gt;</span></span>);
}

<span class="hljs-comment">// User types fast: "r" → "re" → "rea" → "reac" → "react"</span>
<span class="hljs-comment">// 5 requests fired!</span>
<span class="hljs-comment">// 😱 Results arrive in random order!</span>
<span class="hljs-comment">// 😱 Shows results for "rea" even though query is "react"!</span>
<span class="hljs-comment">// User confused: "Why am I seeing results for 'rea'?"</span>

<span class="hljs-comment">// ✅ Fix with AbortController:</span>
useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> controller = <span class="hljs-keyword">new</span> AbortController();

  searchAPI(query, { <span class="hljs-attr">signal</span>: controller.signal })
    .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> setResults(data))
    .catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
      <span class="hljs-keyword">if</span> (err.name !== <span class="hljs-string">'AbortError'</span>) <span class="hljs-built_in">console</span>.error(err);
    });

  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> controller.abort();
}, [query]);

<span class="hljs-comment">// Now only the last search completes! ✨</span>
</code></pre>
<pre><code class="lang-javascript">🔥 Real Bug Examples:

Bug <span class="hljs-number">2</span>: Product Page

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductPage</span>(<span class="hljs-params">{ productId }</span>) </span>{
  <span class="hljs-keyword">const</span> [product, setProduct] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [reviews, setReviews] = useState([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// 🚨 Two independent race conditions!</span>
    fetchProduct(productId).then(setProduct);
    fetchReviews(productId).then(setReviews);
  }, [productId]);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{product?.name}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Reviews</span> <span class="hljs-attr">reviews</span>=<span class="hljs-string">{reviews}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// Bug:</span>
<span class="hljs-comment">// 1. User on Product #1</span>
<span class="hljs-comment">// 2. Clicks Product #2</span>
<span class="hljs-comment">// 3. Product #2 data loads fast ✅</span>
<span class="hljs-comment">// 4. Product #1 reviews load slow</span>
<span class="hljs-comment">// 5. 😱 Shows Product #2 details with Product #1 reviews!</span>
<span class="hljs-comment">// Mismatch! Wrong reviews displayed!</span>

<span class="hljs-comment">// ✅ Fix: Abort both requests</span>
useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> controller = <span class="hljs-keyword">new</span> AbortController();

  <span class="hljs-built_in">Promise</span>.all([
    fetchProduct(productId, { <span class="hljs-attr">signal</span>: controller.signal }),
    fetchReviews(productId, { <span class="hljs-attr">signal</span>: controller.signal })
  ])
    .then(<span class="hljs-function">(<span class="hljs-params">[productData, reviewsData]</span>) =&gt;</span> {
      setProduct(productData);
      setReviews(reviewsData);
    })
    .catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
      <span class="hljs-keyword">if</span> (err.name !== <span class="hljs-string">'AbortError'</span>) <span class="hljs-built_in">console</span>.error(err);
    });

  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> controller.abort();
}, [productId]);
</code></pre>
<pre><code class="lang-javascript">💪 Axios <span class="hljs-keyword">with</span> Cancellation:

<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DataFetcher</span>(<span class="hljs-params">{ id }</span>) </span>{
  <span class="hljs-keyword">const</span> [data, setData] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// ✨ Create cancel token</span>
    <span class="hljs-keyword">const</span> source = axios.CancelToken.source();

    axios.get(<span class="hljs-string">`/api/data/<span class="hljs-subst">${id}</span>`</span>, {
      <span class="hljs-attr">cancelToken</span>: source.token
    })
      .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
        setData(response.data);
      })
      .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
        <span class="hljs-keyword">if</span> (!axios.isCancel(error)) {
          <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error:'</span>, error);
        }
      });

    <span class="hljs-comment">// ✨ Cancel on cleanup</span>
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      source.cancel(<span class="hljs-string">'Component unmounted or id changed'</span>);
    };
  }, [id]);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{data?.name}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<pre><code class="lang-javascript">🔥 React Query - Built-<span class="hljs-keyword">in</span> Cancellation:

<span class="hljs-keyword">import</span> { useQuery } <span class="hljs-keyword">from</span> <span class="hljs-string">'@tanstack/react-query'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserProfile</span>(<span class="hljs-params">{ userId }</span>) </span>{
  <span class="hljs-comment">// ✨ React Query handles race conditions automatically!</span>
  <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: user, isLoading, error } = useQuery({
    <span class="hljs-attr">queryKey</span>: [<span class="hljs-string">'user'</span>, userId],
    <span class="hljs-attr">queryFn</span>: <span class="hljs-function">() =&gt;</span> fetchUser(userId)
  });

  <span class="hljs-keyword">if</span> (isLoading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Spinner</span> /&gt;</span></span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Error</span> <span class="hljs-attr">error</span>=<span class="hljs-string">{error}</span> /&gt;</span></span>;

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

<span class="hljs-comment">// React Query automatically:</span>
<span class="hljs-comment">// 1. Cancels old requests</span>
<span class="hljs-comment">// 2. Deduplicates requests</span>
<span class="hljs-comment">// 3. Caches results</span>
<span class="hljs-comment">// 4. Handles race conditions</span>
<span class="hljs-comment">// No manual cleanup needed! 🎉</span>
</code></pre>
<pre><code class="lang-javascript">😍 SWR Alternative:

<span class="hljs-keyword">import</span> useSWR <span class="hljs-keyword">from</span> <span class="hljs-string">'swr'</span>;

<span class="hljs-keyword">const</span> fetcher = <span class="hljs-function">(<span class="hljs-params">url</span>) =&gt;</span> fetch(url).then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json());

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserProfile</span>(<span class="hljs-params">{ userId }</span>) </span>{
  <span class="hljs-comment">// ✨ SWR handles race conditions too!</span>
  <span class="hljs-keyword">const</span> { <span class="hljs-attr">data</span>: user, error, isLoading } = useSWR(
    <span class="hljs-string">`/api/users/<span class="hljs-subst">${userId}</span>`</span>,
    fetcher
  );

  <span class="hljs-keyword">if</span> (isLoading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Spinner</span> /&gt;</span></span>;
  <span class="hljs-keyword">if</span> (error) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Error</span> <span class="hljs-attr">error</span>=<span class="hljs-string">{error}</span> /&gt;</span></span>;

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}

<span class="hljs-comment">// SWR benefits:</span>
<span class="hljs-comment">// - Automatic race condition handling</span>
<span class="hljs-comment">// - Caching</span>
<span class="hljs-comment">// - Revalidation</span>
<span class="hljs-comment">// - Focus revalidation</span>
</code></pre>
<pre><code class="lang-javascript">🚨 Common Mistakes:

<span class="hljs-comment">// ❌ MISTAKE #1: Aborting but not handling the error</span>
useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> controller = <span class="hljs-keyword">new</span> AbortController();

  fetch(url, { <span class="hljs-attr">signal</span>: controller.signal })
    .then(<span class="hljs-function"><span class="hljs-params">res</span> =&gt;</span> res.json())
    .then(setData);
    <span class="hljs-comment">// 🚨 No .catch! AbortError will be unhandled!</span>

  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> controller.abort();
}, [url]);

<span class="hljs-comment">// ✅ FIX: Always catch AbortError</span>
.catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> {
  <span class="hljs-keyword">if</span> (err.name !== <span class="hljs-string">'AbortError'</span>) {
    <span class="hljs-built_in">console</span>.error(err);
  }
});

<span class="hljs-comment">// ❌ MISTAKE #2: Forgetting to pass signal</span>
useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> controller = <span class="hljs-keyword">new</span> AbortController();

  fetch(url);  <span class="hljs-comment">// 🚨 Missing { signal: controller.signal }!</span>

  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> controller.abort();  <span class="hljs-comment">// Does nothing!</span>
}, [url]);

<span class="hljs-comment">// ✅ FIX: Pass signal to fetch</span>
fetch(url, { <span class="hljs-attr">signal</span>: controller.signal });
</code></pre>
<pre><code class="lang-javascript">🚨 Common Mistakes:

<span class="hljs-comment">// ❌ MISTAKE #3: Creating new controller on every render</span>
<span class="hljs-keyword">const</span> controller = <span class="hljs-keyword">new</span> AbortController();  <span class="hljs-comment">// 🚨 Outside useEffect!</span>

useEffect(<span class="hljs-function">() =&gt;</span> {
  fetch(url, { <span class="hljs-attr">signal</span>: controller.signal });
  <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> controller.abort();
}, [url]);

<span class="hljs-comment">// ✅ FIX: Create inside useEffect</span>
useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> controller = <span class="hljs-keyword">new</span> AbortController();
  <span class="hljs-comment">// ...</span>
}, [url]);

😍 Ways To Fix:

<span class="hljs-number">1.</span> Add AbortController (manual)
<span class="hljs-number">2.</span> Add isCurrent flag (manual)
<span class="hljs-number">3.</span> Use React Query (automatic)
<span class="hljs-number">4.</span> Use SWR (automatic)
</code></pre>
<hr />
<h2 id="heading-9-reacts-anti-pattern-using-index-as-a-key"><strong>9. React's Anti-Pattern: Using Index As a Key</strong></h2>
<p>Using array index as key? You're creating silent bugs that corrupt user data! This mistake breaks forms, loses selections, and causes weird UI glitches.</p>
<p><strong>The Problem:</strong></p>
<p>Using index as key seems to work, but causes subtle bugs that are IMPOSSIBLE to debug!</p>
<pre><code class="lang-javascript">❌ The Index Key Disaster:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TodoList</span>(<span class="hljs-params">{ todos }</span>) </span>{
  <span class="hljs-keyword">return</span> todos.map(<span class="hljs-function">(<span class="hljs-params">todo, index</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TodoItem</span> 
      <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>  // 🚨 <span class="hljs-attr">DANGEROUS</span>!
      <span class="hljs-attr">todo</span>=<span class="hljs-string">{todo}</span>
    /&gt;</span></span>
  ));
}

<span class="hljs-comment">// Looks fine, but watch what happens...</span>

<span class="hljs-comment">// Initial list:</span>
<span class="hljs-comment">// [0] Buy milk</span>
<span class="hljs-comment">// [1] Walk dog</span>
<span class="hljs-comment">// [2] Code review</span>

<span class="hljs-comment">// User deletes "Walk dog" (index 1)</span>
<span class="hljs-comment">// React sees keys: 0, 1</span>
<span class="hljs-comment">// Old keys were: 0, 1, 2</span>

<span class="hljs-comment">// React thinks:</span>
<span class="hljs-comment">// - Key 0: Still there ✓</span>
<span class="hljs-comment">// - Key 1: Still there, but CONTENT changed (was "Walk dog", now "Code review")</span>
<span class="hljs-comment">// - Key 2: Removed</span>

<span class="hljs-comment">// 😱 React re-renders key 1 with NEW content!</span>
<span class="hljs-comment">// 😱 If TodoItem has internal state (checkbox, input), it's PRESERVED!</span>
<span class="hljs-comment">// 😱 User checked "Walk dog", but now "Code review" is checked!</span>
</code></pre>
<pre><code class="lang-javascript">🔥 Real Bug Example - Checkbox Corruption:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TodoItem</span>(<span class="hljs-params">{ todo }</span>) </span>{
  <span class="hljs-keyword">const</span> [isEditing, setIsEditing] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [inputValue, setInputValue] = useState(todo.text);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"checkbox"</span> <span class="hljs-attr">defaultChecked</span>=<span class="hljs-string">{todo.completed}</span> /&gt;</span>

      {isEditing ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> 
          <span class="hljs-attr">value</span>=<span class="hljs-string">{inputValue}</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setInputValue(e.target.value)}
        /&gt;
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>{todo.text}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      )}

      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsEditing(!isEditing)}&gt;Edit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TodoList</span>(<span class="hljs-params">{ todos }</span>) </span>{
  <span class="hljs-keyword">return</span> todos.map(<span class="hljs-function">(<span class="hljs-params">todo, index</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TodoItem</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">todo</span>=<span class="hljs-string">{todo}</span> /&gt;</span></span>  <span class="hljs-comment">// 🚨 BUG!</span>
  ));
}

<span class="hljs-comment">// Bug reproduction:</span>
<span class="hljs-comment">// 1. User checks "Buy milk" (index 0)</span>
<span class="hljs-comment">// 2. User starts editing "Walk dog" (index 1)</span>
<span class="hljs-comment">// 3. User deletes "Buy milk" (index 0)</span>
<span class="hljs-comment">// 4. 😱 "Walk dog" moves to index 0</span>
<span class="hljs-comment">// 5. 😱 But React preserves state for index 0!</span>
<span class="hljs-comment">// 6. 😱 "Walk dog" now shows as checked (was "Buy milk")</span>
<span class="hljs-comment">// 7. 😱 Edit mode is lost!</span>
<span class="hljs-comment">// User data corrupted! 💀</span>
</code></pre>
<pre><code class="lang-javascript">✅ The Correct Way - Stable ID:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TodoList</span>(<span class="hljs-params">{ todos }</span>) </span>{
  <span class="hljs-keyword">return</span> todos.map(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TodoItem</span> 
      <span class="hljs-attr">key</span>=<span class="hljs-string">{todo.id}</span>  // ✨ <span class="hljs-attr">Use</span> <span class="hljs-attr">unique</span>, <span class="hljs-attr">stable</span> <span class="hljs-attr">ID</span>!
      <span class="hljs-attr">todo</span>=<span class="hljs-string">{todo}</span>
    /&gt;</span></span>
  ));
}

<span class="hljs-comment">// Now when "Walk dog" is deleted:</span>
<span class="hljs-comment">// React sees keys: "abc123", "xyz789"</span>
<span class="hljs-comment">// Old keys were: "abc123", "def456", "xyz789"</span>

<span class="hljs-comment">// React thinks:</span>
<span class="hljs-comment">// - "abc123": Still there ✓</span>
<span class="hljs-comment">// - "def456": Removed! Unmount it</span>
<span class="hljs-comment">// - "xyz789": Still there ✓</span>

<span class="hljs-comment">// ✨ React correctly removes the middle item!</span>
<span class="hljs-comment">// ✨ No state confusion!</span>
<span class="hljs-comment">// ✨ Checkboxes stay with correct items!</span>
</code></pre>
<pre><code class="lang-javascript">💪 When You Don<span class="hljs-string">'t Have IDs:

// ❌ DON'</span>T: Use index
todos.map(<span class="hljs-function">(<span class="hljs-params">todo, index</span>) =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Item</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> /&gt;</span></span>)

<span class="hljs-comment">// ❌ DON'T: Generate random keys</span>
todos.map(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Item</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{Math.random()}</span> /&gt;</span></span>)
<span class="hljs-comment">// Random keys remount components every render!</span>

<span class="hljs-comment">// ✅ DO: Generate stable IDs once</span>
<span class="hljs-keyword">const</span> todosWithIds = todos.map(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> ({
  ...todo,
  <span class="hljs-attr">id</span>: todo.id || <span class="hljs-string">`<span class="hljs-subst">${todo.text}</span>-<span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now()}</span>-<span class="hljs-subst">${<span class="hljs-built_in">Math</span>.random()}</span>`</span>
}));

<span class="hljs-comment">// ✅ DO: Use UUID library</span>
<span class="hljs-keyword">import</span> { v4 <span class="hljs-keyword">as</span> uuidv4 } <span class="hljs-keyword">from</span> <span class="hljs-string">'uuid'</span>;

<span class="hljs-keyword">const</span> addTodo = <span class="hljs-function">(<span class="hljs-params">text</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> newTodo = {
    <span class="hljs-attr">id</span>: uuidv4(),  <span class="hljs-comment">// Generates unique ID</span>
    text,
    <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>
  };
  setTodos([...todos, newTodo]);
};

<span class="hljs-comment">// ✅ DO: Use crypto.randomUUID (modern browsers)</span>
<span class="hljs-keyword">const</span> newTodo = {
  <span class="hljs-attr">id</span>: crypto.randomUUID(),  <span class="hljs-comment">// Native browser API!</span>
  <span class="hljs-attr">text</span>: <span class="hljs-string">'New task'</span>
};
</code></pre>
<pre><code class="lang-javascript">⚡️When Index IS Okay:

<span class="hljs-comment">// ✅ ONLY use index when ALL these are true:</span>

<span class="hljs-comment">// 1. List never reorders</span>
<span class="hljs-comment">// 2. List never filters</span>
<span class="hljs-comment">// 3. List never adds/removes items</span>
<span class="hljs-comment">// 4. Items have no internal state</span>
<span class="hljs-comment">// 5. List is purely static display</span>

<span class="hljs-comment">// Example - Static display list:</span>
<span class="hljs-keyword">const</span> FEATURES = [<span class="hljs-string">'Fast'</span>, <span class="hljs-string">'Secure'</span>, <span class="hljs-string">'Reliable'</span>];

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">FeatureList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> FEATURES.map(<span class="hljs-function">(<span class="hljs-params">feature, index</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>  {/* ✅ OK here - list never changes */}
      {feature}
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  ));
}

<span class="hljs-comment">// But if list CAN change → use IDs!</span>
</code></pre>
<pre><code class="lang-javascript">✅ Generating Keys - The Right Way:

<span class="hljs-comment">// ✅ Option 1: Backend provides IDs</span>
<span class="hljs-keyword">const</span> todos = [
  { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'Buy milk'</span> },
  { <span class="hljs-attr">id</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'Walk dog'</span> }
];

<span class="hljs-comment">// ✅ Option 2: Generate when adding</span>
<span class="hljs-keyword">const</span> [todos, setTodos] = useState([]);

<span class="hljs-keyword">const</span> addTodo = <span class="hljs-function">(<span class="hljs-params">text</span>) =&gt;</span> {
  setTodos([
    ...todos,
    {
      <span class="hljs-attr">id</span>: <span class="hljs-built_in">Date</span>.now(),  <span class="hljs-comment">// Timestamp as ID (good for local state)</span>
      text
    }
  ]);
};

<span class="hljs-comment">// ✅ Option 3: UUID library</span>
<span class="hljs-keyword">import</span> { v4 <span class="hljs-keyword">as</span> uuidv4 } <span class="hljs-keyword">from</span> <span class="hljs-string">'uuid'</span>;

<span class="hljs-keyword">const</span> addTodo = <span class="hljs-function">(<span class="hljs-params">text</span>) =&gt;</span> {
  setTodos([
    ...todos,
    {
      <span class="hljs-attr">id</span>: uuidv4(),  <span class="hljs-comment">// Universally unique</span>
      text
    }
  ]);
};

<span class="hljs-comment">// ✅ Option 4: Crypto API (no dependencies!)</span>
<span class="hljs-keyword">const</span> addTodo = <span class="hljs-function">(<span class="hljs-params">text</span>) =&gt;</span> {
  setTodos([
    ...todos,
    {
      <span class="hljs-attr">id</span>: crypto.randomUUID(),  <span class="hljs-comment">// Browser native!</span>
      text
    }
  ]);
};

<span class="hljs-comment">// ✅ Option 5: Compound key for nested lists</span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TodoItem</span> 
  <span class="hljs-attr">key</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">todoId</span>}<span class="hljs-attr">-</span>${<span class="hljs-attr">subtaskId</span>}`}  // <span class="hljs-attr">Combine</span> <span class="hljs-attr">parent</span> + <span class="hljs-attr">child</span> <span class="hljs-attr">ID</span>
  <span class="hljs-attr">task</span>=<span class="hljs-string">{subtask}</span>
/&gt;</span></span>
</code></pre>
<pre><code class="lang-javascript">📊 The Performance Impact:

Scenario: List <span class="hljs-keyword">of</span> <span class="hljs-number">1000</span> items, <span class="hljs-keyword">delete</span> one <span class="hljs-keyword">from</span> middle

❌ With index keys:
 - React re-renders ALL <span class="hljs-number">999</span> remaining items
 - Each item<span class="hljs-string">'s state potentially corrupted
 - Time: 450ms
 - Bugs: Many! 🐛🐛🐛

✅ With proper IDs:
 - React removes exactly 1 item
 - Other 999 items unchanged
 - Time: 5ms
 - Bugs: None! ✨

 90x faster + zero bugs!</span>
</code></pre>
<hr />
<h2 id="heading-10-react-pro-secret-the-data-fetching-in-parallel-pattern"><strong>10. React Pro Secret: The "Data Fetching in Parallel" Pattern</strong></h2>
<p>Stop waiting for API calls one-by-one! Fetch in parallel and cut your loading time by 70%. This is how the pros do it!</p>
<p><strong>The Problem:</strong></p>
<p>Sequential API calls make users wait unnecessarily. Each request blocks the next one!</p>
<pre><code class="lang-javascript">❌ Slow Sequential Fetching:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [user, setUser] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);
  <span class="hljs-keyword">const</span> [comments, setComments] = useState([]);
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">true</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-comment">// 🚨 Waits at-least 1s for user</span>
      <span class="hljs-keyword">const</span> userData = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/user'</span>).then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.json());
      setUser(userData);

      <span class="hljs-comment">// 🚨 Waits at-least 1s for posts</span>
      <span class="hljs-keyword">const</span> postsData = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/posts'</span>).then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.json());
      setPosts(postsData);

      <span class="hljs-comment">// 🚨 Waits at-least 1s for comments</span>
      <span class="hljs-keyword">const</span> commentsData = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/api/comments'</span>).then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.json());
      setComments(commentsData);

      setLoading(<span class="hljs-literal">false</span>);
    };

    fetchData();
  }, []);

  <span class="hljs-comment">// Total time: at-least 3 seconds! 😱</span>

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Spinner</span> /&gt;</span></span>;
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<pre><code class="lang-javascript">✅ Fast Parallel Fetching:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [user, setUser] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);
  <span class="hljs-keyword">const</span> [comments, setComments] = useState([]);
  <span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">true</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> fetchData = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-comment">// ✨ All requests fire at once!</span>
      <span class="hljs-keyword">const</span> [userData, postsData, commentsData] = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all([
        fetch(<span class="hljs-string">'/api/user'</span>).then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.json()),
        fetch(<span class="hljs-string">'/api/posts'</span>).then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.json()),
        fetch(<span class="hljs-string">'/api/comments'</span>).then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.json())
      ]);

      setUser(userData);
      setPosts(postsData);
      setComments(commentsData);
      setLoading(<span class="hljs-literal">false</span>);
    };

    fetchData();
  }, []);

  <span class="hljs-comment">// Total time: 1 second (fastest request)! 🎉</span>

  <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Spinner</span> /&gt;</span></span>;
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
}
</code></pre>
<pre><code class="lang-javascript">🔥 Better - Show Data <span class="hljs-keyword">as</span> It Arrives:

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [user, setUser] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [posts, setPosts] = useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [comments, setComments] = useState(<span class="hljs-literal">null</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// ✨ Fire all requests, update as each completes</span>
    fetch(<span class="hljs-string">'/api/user'</span>)
      .then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.json())
      .then(setUser);

    fetch(<span class="hljs-string">'/api/posts'</span>)
      .then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.json())
      .then(setPosts);

    fetch(<span class="hljs-string">'/api/comments'</span>)
      .then(<span class="hljs-function"><span class="hljs-params">r</span> =&gt;</span> r.json())
      .then(setComments);
  }, []);

  <span class="hljs-comment">// ✨ Show each section as data arrives!</span>
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {user ? <span class="hljs-tag">&lt;<span class="hljs-name">UserProfile</span> <span class="hljs-attr">user</span>=<span class="hljs-string">{user}</span> /&gt;</span> : <span class="hljs-tag">&lt;<span class="hljs-name">UserSkeleton</span> /&gt;</span>}
      {posts ? <span class="hljs-tag">&lt;<span class="hljs-name">PostsList</span> <span class="hljs-attr">posts</span>=<span class="hljs-string">{posts}</span> /&gt;</span> : <span class="hljs-tag">&lt;<span class="hljs-name">PostsSkeleton</span> /&gt;</span>}
      {comments ? <span class="hljs-tag">&lt;<span class="hljs-name">CommentsFeed</span> <span class="hljs-attr">comments</span>=<span class="hljs-string">{comments}</span> /&gt;</span> : <span class="hljs-tag">&lt;<span class="hljs-name">CommentsSkeleton</span> /&gt;</span>}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-comment">// User sees content progressively - much better UX! 🎨</span>
</code></pre>
<pre><code class="lang-javascript">✨ Key Methods:

<span class="hljs-comment">// Promise.all - Wait for all, fail if any fails</span>
<span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all([fetch1, fetch2, fetch3]);

<span class="hljs-comment">// Promise.allSettled - Wait for all, never fails</span>
<span class="hljs-keyword">const</span> results = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.allSettled([fetch1, fetch2, fetch3]);

<span class="hljs-comment">// Promise.race - Use first to complete</span>
<span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.race([fetch1, fetch2, fetch3]);

<span class="hljs-comment">// Promise.any - Use first success, fail only if all fail</span>
<span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.any([fetch1, fetch2, fetch3]);

💡 When to Use Each:

<span class="hljs-built_in">Promise</span>.all: All requests must succeed (<span class="hljs-keyword">default</span> choice)
<span class="hljs-built_in">Promise</span>.allSettled: Some can fail, show partial data
<span class="hljs-built_in">Promise</span>.race: Use fastest response (redundant APIs)
<span class="hljs-built_in">Promise</span>.any: Fallback APIs (use first working one)
</code></pre>
<h3 id="heading-found-these-tips-useful-download-the-complete-ebook-with-50-such-react-tips-from-react-50-pro-tips-ebookhttpscoursesyogeshchavandevreact-50-pro-tips-ebook">Found these tips useful? Download the complete ebook with 50+ such React tips from <a target="_blank" href="https://courses.yogeshchavan.dev/react-50-pro-tips-ebook">React 50+ Pro Tips Ebook</a>.</h3>
<h1 id="heading-connect-with-me"><strong>Connect With Me</strong></h1>
<ul>
<li><p><a target="_blank" href="https://courses.yogeshchavan.dev/"><strong>Check out my all courses</strong></a></p>
</li>
<li><p><a target="_blank" href="https://github.com/myogeshchavan97"><strong>GitHub</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[The Most Powerful, Easy To Use And Best State Management Library in React]]></title><description><![CDATA[Zustand state management library is recently gaining a lot of popularity compared to Redux toolkit. It also has more downloads and GitHub stars than redux toolkit as you can see below.
Zustand vs Redux Toolkit Usage

Weekly Downloads Zustand vs Redux...]]></description><link>https://blog.yogeshchavan.dev/the-most-powerful-easy-to-use-and-best-state-management-library-in-react</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/the-most-powerful-easy-to-use-and-best-state-management-library-in-react</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Sun, 03 Aug 2025 09:41:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754214020817/749f4915-5afe-4019-b2ac-63fba94ee298.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Zustand state management library is recently gaining a lot of popularity compared to Redux toolkit. It also has more downloads and GitHub stars than redux toolkit as you can see below.</p>
<h2 id="heading-zustand-vs-redux-toolkit-usage">Zustand vs Redux Toolkit Usage</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754206103459/9108963e-cfea-4f86-96d7-d51008aa67c9.png" alt="NPM Trends" class="image--center mx-auto" /></p>
<h2 id="heading-weekly-downloads-zustand-vs-redux-toolkit">Weekly Downloads Zustand vs Redux Toolkit</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754206268900/a7ccd751-ab07-40a9-90c8-75f100c59086.png" alt="Weekly Downloads" class="image--center mx-auto" /></p>
<p>Many industry projects are nowadays preferrring Zustand for creating applications. So in this article you will learn how to get started with Zustand in a React application.</p>
<p>So let’s get started.</p>
<hr />
<p><a target="_blank" href="https://zustand-demo.pmnd.rs/">Zustand</a> is a simple and fast state management library for React applications. It is easy to use, especially for beginners, and a great alternative to more complex libraries like Redux and Redux Toolkit.</p>
<h2 id="heading-why-use-zustand"><strong>Why Use Zustand?</strong></h2>
<ul>
<li><p><strong>Very easy to learn</strong>: Minimal API surface and very little setup required.</p>
</li>
<li><p><strong>Small and fast</strong>: Less bundle size and efficient updates.</p>
</li>
<li><p><strong>Works with hooks</strong>: Feels native to modern React development.</p>
</li>
<li><p><strong>No provider needed</strong>: Just one function and you're set!</p>
</li>
</ul>
<h2 id="heading-why-zustand-over-redux"><strong>Why Zustand over Redux?</strong></h2>
<ul>
<li><p>Less boilerplate</p>
</li>
<li><p>Simple and un-opinionated</p>
</li>
<li><p>Makes hooks the primary means of consuming state</p>
</li>
</ul>
<h2 id="heading-why-zustand-over-context"><strong>Why Zustand over Context?</strong></h2>
<ul>
<li><p>Less boilerplate</p>
</li>
<li><p>Renders components only on store data used in component changes</p>
</li>
<li><p>Centralized, action-based state management</p>
</li>
</ul>
<p><strong>Want to learn through video? click the link below for a preview video</strong> <a target="_blank" href="https://master-zustand.yogeshchavan.dev/"><strong>from my Zustand Course</strong></a><strong>.</strong></p>
<p>For more such FREE previews, check out the course page.</p>
<p><a target="_blank" href="https://res.cloudinary.com/dyatqxvue/video/upload/v1754211410/Zustand/cp8nxs2qe8esh0ukxmqr.mp4"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754211877928/4fde9495-8581-47ee-8093-8891b608353b.png" alt class="image--center mx-auto" /></a></p>
<h2 id="heading-installing-zustand"><strong>Installing Zustand</strong></h2>
<p>To add Zustand to your React project, execute the following command in your terminal:</p>
<pre><code class="lang-javascript">npm install zustand
</code></pre>
<h2 id="heading-core-concepts"><strong>Core Concepts</strong></h2>
<ul>
<li><p><strong>Store</strong>: Central place to keep your state and the functions (actions) to change it.</p>
</li>
<li><p><strong>State</strong>: The data you want to keep track of.</p>
</li>
<li><p><strong>Actions</strong>: Functions that update the state.</p>
</li>
<li><p><strong>Hooks</strong>: Functions you use inside your components to read and update the state.</p>
</li>
</ul>
<h2 id="heading-basic-example-counter-app"><strong>Basic Example: Counter App</strong></h2>
<p>Let's go through a simple example, a counter app:</p>
<h2 id="heading-1-create-the-store"><strong>1. Create the Store</strong></h2>
<p>First, make a new file (for example, <code>store/counterStore.js</code>):</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { create } <span class="hljs-keyword">from</span> <span class="hljs-string">'zustand'</span>

<span class="hljs-keyword">const</span> useCounterStore = create(<span class="hljs-function">(<span class="hljs-params">set, get</span>) =&gt;</span> ({
  <span class="hljs-attr">count</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">increment</span>: <span class="hljs-function">() =&gt;</span> set({ <span class="hljs-attr">count</span>: get().count + <span class="hljs-number">1</span> }),
  <span class="hljs-attr">decrement</span>: <span class="hljs-function">() =&gt;</span> set({ <span class="hljs-attr">count</span>: get().count - <span class="hljs-number">1</span> })
}));

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> useCounterStore;
</code></pre>
<p>This store defines:</p>
<ul>
<li><p><code>count</code>: the state variable</p>
</li>
<li><p><code>increment</code> and <code>decrement</code>: actions (functions) to update the <code>count</code></p>
</li>
</ul>
<p>Note that, we have given <code>useCounterStore</code> as the name for the store, because every store created with Zustand is a custom which which we can directly access in any of the functional component.</p>
<h2 id="heading-2-use-the-store-in-a-component"><strong>2. Use the Store in a Component</strong></h2>
<p>In your React component (e.g., <code>Counter.js</code>):</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>
<span class="hljs-keyword">import</span> useCounterStore <span class="hljs-keyword">from</span> <span class="hljs-string">'./store/counterStore'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Counter</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> count = useCounterStore(<span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.count);
  <span class="hljs-keyword">const</span> increment = useCounterStore(<span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.increment);
  <span class="hljs-keyword">const</span> decrement = useCounterStore(<span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.decrement);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Count: {count}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{increment}</span>&gt;</span>Increment<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{decrement}</span>&gt;</span>Decrement<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Counter
</code></pre>
<p>That’s it!</p>
<p>This way you can create as many stores as you want, one for storing profile information, another for storing authentication information and so on.</p>
<p>Also, as you can see, to use Zustand store, you don’t need to write a lot of boilerplate code like Redux or Redux Toolkit.</p>
<p>You also don’t need to wrap your entire application with the Provider component from <code>react-redux</code>.</p>
<p>So using Zustand, makes it to really easy to manage state of your entire application.</p>
<h2 id="heading-how-zustand-works"><strong>How Zustand Works</strong></h2>
<ul>
<li><p><strong>Direct store usage</strong>: Components call the <code>useCounterStore</code> hook directly.</p>
</li>
<li><p><strong>Automatic updates</strong>: Zustand ensures your components re-render only when the part of the state they use changes.</p>
</li>
<li><p><strong>No boilerplate or provider</strong>: Just create the store and use it; no extra setup needed.</p>
</li>
</ul>
<h2 id="heading-when-should-you-use-zustand"><strong>When Should You Use Zustand?</strong></h2>
<ul>
<li><p>Managing shared or global state (e.g., theme, authentication, shopping cart).</p>
</li>
<li><p>When <code>useState</code> and <code>useContext</code> become hard to manage.</p>
</li>
<li><p>In both small and large applications - Zustand scales easily.</p>
</li>
</ul>
<h2 id="heading-extra-features"><strong>Extra Features</strong></h2>
<ul>
<li><p><strong>Selectors</strong>: Access only parts of the state to avoid unnecessary re-renders.</p>
</li>
<li><p><strong>Middleware support</strong>: Add features like logging or persistence easily.</p>
</li>
<li><p><strong>Multiple stores</strong>: Split state into smaller stores for bigger apps.</p>
</li>
<li><p><strong>Works with TypeScript</strong>: Define types for safety and better developer experience.</p>
</li>
</ul>
<h2 id="heading-summary-table-key-concepts"><strong>Summary Table: Key Concepts</strong></h2>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Concept</strong></td><td><strong>Description</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Store</td><td>Central object for state and actions</td></tr>
<tr>
<td>State</td><td>Data kept in the store (e.g., <code>count</code>)</td></tr>
<tr>
<td>Action</td><td>Function to update the state (<code>increment</code>)</td></tr>
<tr>
<td>Hook</td><td>Used to access store in components (<code>useCounterStore</code>)</td></tr>
</tbody>
</table>
</div><blockquote>
<p><strong>Learn Zustand Basics and Build 2 large applications using React + TypeScript + Zustand + React Hook Form + Zod Validation</strong> <a target="_blank" href="https://master-zustand.yogeshchavan.dev/"><strong>in this video course</strong></a><strong>.</strong> <strong>Bonus Offer Available Only For Today.</strong></p>
</blockquote>
<h2 id="heading-build-ecommerce-app-using-zustand-application-demo"><strong>Build Ecommerce App Using Zustand - Application Demo</strong></h2>
<p><a target="_blank" href="https://res.cloudinary.com/dyatqxvue/video/upload/v1754128475/Zustand/hfpj4eyr8zbhwjubbb6x.mp4"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754212001580/1fb64866-38dc-470b-ba00-78d5c6d027bf.png" alt="Ecommerce App" class="image--center mx-auto" /></a></p>
<h1 id="heading-connect-with-me"><strong>Connect With Me</strong></h1>
<ul>
<li><p><a target="_blank" href="https://courses.yogeshchavan.dev/"><strong>Check out my other courses</strong></a></p>
</li>
<li><p><a target="_blank" href="https://github.com/myogeshchavan97"><strong>GitHub</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Lost in Transition: How to Downgrade to Tailwind CSS v3 in Next.js And React.js]]></title><description><![CDATA[The recent release of Tailwind CSS v4 has brought about significant changes. 
One of the most noticeable differences is the absence of a tailwind.config.js file when creating a new Next.js application. This has left many developers confused, especial...]]></description><link>https://blog.yogeshchavan.dev/lost-in-transition-how-to-downgrade-to-tailwind-css-v3-in-nextjs-and-reactjs</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/lost-in-transition-how-to-downgrade-to-tailwind-css-v3-in-nextjs-and-reactjs</guid><category><![CDATA[React]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Tailwind CSS]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Mon, 10 Mar 2025 09:17:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741598105790/f2993332-9551-4a0c-8f61-6a2daf4d3f9a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The recent release of Tailwind CSS v4 has brought about significant changes. </p>
<p>One of the most noticeable differences is the absence of a <code>tailwind.config.js</code> file when creating a new Next.js application. This has left many developers confused, especially when trying to follow tutorials or videos that use Tailwind CSS v3.</p>
<p>While mentoring on <a target="_blank" href="https://www.codementor.io/@myogeshchavan97">Codementor</a>, I have seen many developers struggling with this issue.</p>
<p>If you're one of them, don't worry! Here's a step-by-step guide on how to use Tailwind CSS v3 in your Next.js and React.js project.</p>
<h2 id="heading-why-downgrade-to-tailwind-css-v3"><strong>Why Downgrade to Tailwind CSS v3?</strong></h2>
<p>While Tailwind CSS v4 offers many exciting features, some developers might prefer to stick with v3 for various reasons, such as compatibility issues or familiarity with existing projects. Whatever your reason, downgrading is straightforward.</p>
<h2 id="heading-steps-to-downgrade-to-tailwind-css-v3"><strong>Steps to Downgrade to Tailwind CSS v3</strong></h2>
<h3 id="heading-step-1-uninstall-tailwind-css-v4"><strong>Step 1: Uninstall Tailwind CSS v4</strong></h3>
<p>First, you need to uninstall the installed Tailwind CSS v4. You can do this by running the following command in your terminal:</p>
<pre><code class="lang-javascript">npm uninstall tailwindcss
</code></pre>
<h3 id="heading-step-2-install-tailwind-css-v3"><strong>Step 2: Install Tailwind CSS v3</strong></h3>
<p>Next, install Tailwind CSS v3 along with other necessary dependencies using the following command:</p>
<pre><code class="lang-javascript">npm install -D tailwindcss@<span class="hljs-number">3.4</span><span class="hljs-number">.17</span> postcss autoprefixer
</code></pre>
<h3 id="heading-step-3-create-a-tailwind-config-file"><strong>Step 3: Create a Tailwind Config File</strong></h3>
<p>Now, create a <code>tailwind.config.js</code> file by executing this command:</p>
<pre><code class="lang-javascript">npx tailwindcss init -p
</code></pre>
<h3 id="heading-step-4-configure-the-content-array"><strong>Step 4: Configure the Content Array</strong></h3>
<p>Open the newly created <code>tailwind.config.js</code> file and update the <code>content</code> array to include your project's paths.</p>
<ul>
<li><strong>For Next.js Projects:</strong><br />  Replace the existing content with the following code:</li>
</ul>
<pre><code class="lang-javascript">content: [
  <span class="hljs-string">"./pages/**/*.{js,ts,jsx,tsx,mdx}"</span>,
  <span class="hljs-string">"./components/**/*.{js,ts,jsx,tsx,mdx}"</span>,
  <span class="hljs-string">"./app/**/*.{js,ts,jsx,tsx,mdx}"</span>,
],
</code></pre>
<ul>
<li><strong>For Vite + React.js Projects:</strong><br />  Use the following configuration instead:</li>
</ul>
<pre><code class="lang-javascript">content: [
  <span class="hljs-string">"./pages/**/*.{js,ts,jsx,tsx,mdx}"</span>,
  <span class="hljs-string">"./components/**/*.{js,ts,jsx,tsx,mdx}"</span>,
  <span class="hljs-string">"./app/**/*.{js,ts,jsx,tsx,mdx}"</span>,
],
</code></pre>
<h3 id="heading-step-5-update-your-global-css-file"><strong>Step 5: Update Your Global CSS File</strong></h3>
<p>Finally, add the following lines to your main <code>global.css/index.css</code> file:</p>
<pre><code class="lang-javascript">@tailwind base;
@tailwind components;
@tailwind utilities;
</code></pre>
<h2 id="heading-youre-done"><strong>You're Done!</strong></h2>
<p>By following these steps, you should now have Tailwind CSS v3 up and running in your Next.js and React.js project.</p>
<p>This setup will allow you to continue using the features and configurations you're familiar with from v3, making it easier to follow older tutorials or maintain existing projects.</p>
<p>Happy coding!</p>
<h3 id="heading-connect-with-me"><strong>Connect With Me</strong></h3>
<ul>
<li><p>🔥 <a target="_blank" href="https://courses.yogeshchavan.dev/master-react-in-20-days-training-application-source-code"><strong>Master React In 20 Days Training Application Source Code</strong></a></p>
</li>
<li><p>🚀 <a target="_blank" href="https://courses.yogeshchavan.dev/mastering-next-js-15-from-basics-to-advanced"><strong>Master Next.js 15: From Basics to Advanced</strong></a></p>
</li>
<li><p>📹 <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/"><strong>Connect With Me</strong></a></p>
</li>
<li><p>🔗 <a target="_blank" href="https://github.com/myogeshchavan97"><strong>GitHub</strong></a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[🚀 Master Next.js 15 Like a Pro: Your Ultimate Guide to Modern Web Development!]]></title><description><![CDATA[Web development is evolving faster than ever, and staying ahead in this game means mastering tools that power high-performance, scalable, and SEO-friendly websites. Enter Next.js 15, the latest version of the revolutionary React framework, and the ke...]]></description><link>https://blog.yogeshchavan.dev/master-nextjs-15-like-a-pro-your-ultimate-guide-to-modern-web-development</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/master-nextjs-15-like-a-pro-your-ultimate-guide-to-modern-web-development</guid><category><![CDATA[Next.js]]></category><category><![CDATA[React]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Mon, 20 Jan 2025 08:36:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737362000512/117a7c10-72cf-4e70-9300-0556af6c7f7f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Web development is evolving faster than ever, and staying ahead in this game means mastering tools that power high-performance, scalable, and SEO-friendly websites. Enter <strong>Next.js 15</strong>, the latest version of the revolutionary React framework, and the key to building world-class web applications.</p>
<h2 id="heading-why-should-you-care-about-nextjs-15">Why Should You Care About Next.js 15?</h2>
<p>Next.js isn’t just another framework; it’s the <strong>gold standard</strong> for building modern web applications. With features like:</p>
<ul>
<li><p><strong>Dynamic Routing</strong> for seamless navigation</p>
</li>
<li><p><strong>Server and Client Components</strong> for optimal performance</p>
</li>
<li><p><strong>Server Actions</strong> for API handling</p>
</li>
<li><p><strong>SEO &amp; Image Optimization</strong> for search engine dominance</p>
</li>
</ul>
<p>… mastering Next.js isn’t just a skill, it’s a <strong>superpower</strong> in today’s tech landscape.</p>
<p>But where do you start? How do you go from <strong>beginner</strong> to <strong>expert</strong> without feeling overwhelmed? That’s where <strong>"</strong><a target="_blank" href="https://courses.yogeshchavan.dev/mastering-next-js-15-from-basics-to-advanced"><strong>Mastering Next.js 15: From Basics to Advanced</strong></a><strong>"</strong> comes in!</p>
<h3 id="heading-course-launch-offer-price-10-800-regular-price-19-1520httpscoursesyogeshchavandevall-courses-and-ebooks"><a target="_blank" href="https://courses.yogeshchavan.dev/all-courses-and-ebooks"><strong><mark>Course Launch Offer Price - $10 / ₹800 ( Regular Price <s>$19 / </s></mark></strong> <mark>₹</mark><strong><mark><s>1520</s>)</mark></strong></a></h3>
<hr />
<blockquote>
<p><strong>Check out the FREE preview of video content from the course by</strong> <a target="_blank" href="https://courses.yogeshchavan.dev/mastering-next-js-15-from-basics-to-advanced"><strong>visiting the course page</strong></a><strong>.</strong></p>
</blockquote>
<hr />
<h2 id="heading-whats-inside-the-course"><strong>What’s Inside the Course?</strong></h2>
<p>In <strong>"</strong><a target="_blank" href="https://courses.yogeshchavan.dev/mastering-next-js-15-from-basics-to-advanced"><strong>Mastering Next.js 15: From Basics to Advanced</strong></a><strong>"</strong>, you’ll learn everything you need to know, whether you’re just starting or looking to refine your skills.</p>
<p>🎓 <strong>This Is NOT Your Typical Next.js Course!</strong> 🚀</p>
<p>When it comes to learning, I believe the best way to master something is by <strong>making mistakes and learning from them</strong> — and that’s exactly what sets <strong>"</strong><a target="_blank" href="https://courses.yogeshchavan.dev/mastering-next-js-15-from-basics-to-advanced"><strong>Mastering Next.js 15: From Basics to Advanced</strong></a><strong>"</strong> apart.</p>
<p>In this course, we’re not just writing clean, error-free code. Instead, you’ll dive into <strong>real-world scenarios where errors happen</strong>, just like in actual development.</p>
<p>Here’s what makes this course different.</p>
<p>🔥 <strong>Learn Through Errors</strong><br />I’ll walk you through:</p>
<ul>
<li><p><strong>Understanding the error messages</strong> and their root causes.</p>
</li>
<li><p><strong>Debugging effectively</strong> to pinpoint issues.</p>
</li>
<li><p><strong>Fixing errors step by step</strong>, ensuring you gain the skills and confidence to handle challenges in any project.</p>
</li>
</ul>
<p>💡 By the end of this course, you won’t just know how to build with Next.js—you’ll know how to <strong>troubleshoot, debug, and solve problems</strong>, making you a more resilient and resourceful developer.</p>
<p>Whether you're just starting out or a seasoned developer, this course will help you master Next.js 15’s newest features:</p>
<p>→ Server Actions</p>
<p>→ Advanced Error Handling</p>
<p>→ React 19 Form Hooks</p>
<p>→ React Hook Form With Zod Validation</p>
<p>→ Auth.js (NextAuth v5)</p>
<p>→ Prisma Integration</p>
<p>🔑 <strong>What You’ll Gain:</strong></p>
<p>✅ Master Next.js 15 fundamentals.</p>
<p>✅ Build real-world, production-ready projects.</p>
<p>✅ Learn advanced server-side rendering, server actions, and optimizations.</p>
<p>✅ Manage security issues in server actions and learn how to fix them.</p>
<p>✅ Master Prisma for modern database workflows.</p>
<p>🛠 <strong>What You’ll Learn Inside the Course:</strong></p>
<p>🔹 <strong>Server Actions:</strong> Simplify backend logic by writing server-side operations directly in React components.</p>
<p>🔹 <strong>Error Handling:</strong> Build resilient apps with route-specific error boundaries and customizable error pages.</p>
<p>🔹 <strong>Forms Made Easy:</strong> Learn React 19’s useActionState and useFormStatus and other hooks.</p>
<p>Use react-hook-form with zod validation for user-friendly, scalable forms.</p>
<p><strong>Learn to validate forms at both frontend and backend without duplicating the same logic using zod schema.</strong></p>
<p>🔹 <strong>Prisma Integration:</strong> Manage your database effortlessly with schema design, efficient queries, and smooth migrations.</p>
<p>🔹 <strong>Auth.js (NextAuth v5):</strong> Set up secure, scalable authentication flows for your app using GitHub and Google Authentication.</p>
<p>This course is hands-on, with interactive coding exercises, downloadable resources, and real-world projects that <strong>you can showcase in your portfolio</strong>.</p>
<hr />
<h2 id="heading-who-is-this-course-for"><strong>Who Is This Course For?</strong></h2>
<p>Whether you’re:</p>
<ul>
<li><p>A <strong>beginner</strong> looking to learn Next.js from scratch</p>
</li>
<li><p>A <strong>React developer</strong> eager to expand your skillset</p>
</li>
<li><p>A <strong>professional developer</strong> wanting to stay ahead in the industry</p>
</li>
</ul>
<p>… this course is designed to meet you where you are and take you to the next level.</p>
<hr />
<h2 id="heading-why-choose-this-course"><strong>Why Choose This Course?</strong></h2>
<p>Here’s why <strong>"</strong><a target="_blank" href="https://courses.yogeshchavan.dev/mastering-next-js-15-from-basics-to-advanced"><strong>Mastering Next.js 15: From Basics to Advanced</strong></a><strong>"</strong> stands out:</p>
<ol>
<li><p><strong>Up-to-date content</strong> covering the latest features of Next.js 15.</p>
</li>
<li><p><strong>Project-based learning</strong> — you’ll walk away with project you can show off.</p>
</li>
<li><p><strong>Clear, engaging explanations</strong></p>
</li>
<li><p>Access to an <strong>exclusive discord community</strong> for ongoing support, and to clear your doubts</p>
</li>
</ol>
<hr />
<h2 id="heading-dont-just-take-my-word-for-it"><strong>Don’t Just Take My Word For It…</strong></h2>
<p>Here’s what past students have to say about my courses:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737361649817/62ec2cdd-35a5-4a66-a831-da56433e8217.png" alt="Testimonials" class="image--center mx-auto" /></p>
<h2 id="heading-enroll-now-and-start-building-the-future"><strong>Enroll Now and Start Building the Future!</strong></h2>
<p>Don’t let the world of modern web development pass you by. Take control of your career and master Next.js 15 with this all-encompassing course.</p>
<p>🎯 <a target="_blank" href="https://courses.yogeshchavan.dev/mastering-next-js-15-from-basics-to-advanced"><strong>Enroll Now</strong></a> to take the first step toward becoming a Next.js expert!</p>
<p>🕒 <strong>Limited-Time Offer:</strong> Course launch discounts offer is ending in <strong>2 days(22nd January).</strong></p>
<p>Let’s turn your <strong>dreams into code</strong> and your <strong>code into impact</strong>. See you in the course!</p>
<h2 id="heading-connect-with-me"><strong>Connect With Me</strong></h2>
<ul>
<li><p><a target="_blank" href="https://courses.yogeshchavan.dev/all-courses-and-ebooks">Get All Current + Future Courses/Ebooks At Just $25 / ₹2000</a> <strong>(Offer Ends On 22nd January)</strong></p>
</li>
<li><p>📹 <a target="_blank" href="https://www.youtube.com/@codingmastery_dev">Subscribe on YouTube</a></p>
</li>
<li><p>🔗 <a target="_blank" href="https://github.com/myogeshchavan97">GitHub</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Time is Ticking! Black Friday Sale Ends Today]]></title><description><![CDATA[This is your last chance to get lifetime access to all my current and future courses/ebooks, including the upcoming Next.js 15 Course, for just:
💰 $20 / ₹1600 (originally $132 / ₹10,560)
🎓 Included Courses & Ebooks:

Getting Started With Redux, Red...]]></description><link>https://blog.yogeshchavan.dev/time-is-ticking-black-friday-sale-ends-today</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/time-is-ticking-black-friday-sale-ends-today</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Sat, 30 Nov 2024 05:13:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732943341809/19e97fab-0793-4fbe-88ef-9a67d28e56a0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is your last chance to get lifetime access to all my <a target="_blank" href="https://courses.yogeshchavan.dev/">current and future courses/ebooks</a>, including the upcoming Next.js 15 Course, for just:</p>
<p>💰 <strong>$20 / ₹1600</strong> (originally <strong>$132 / ₹10,560</strong>)</p>
<h1 id="heading-included-courses-amp-ebooks"><strong>🎓 Included Courses &amp; Ebooks:</strong></h1>
<ul>
<li><p>Getting Started With Redux, Redux Toolkit And Becoming Pro (2024 Edition)</p>
</li>
<li><p>Build Book Management App with React + Firebase + Google Books API + Tailwind CSS</p>
</li>
<li><p>Build Library Management System Using React, Shadcn/ui, Supabase, and React Query</p>
</li>
<li><p>MERN Stack Masterclass</p>
</li>
<li><p>Build Expense Manager App Using React And TypeScript</p>
</li>
<li><p>React Router 6 Course</p>
</li>
<li><p>Learn React In 30 Days</p>
</li>
<li><p>Mastering Redux Course</p>
</li>
<li><p>Learn React — 3 Hours Live Masterclass</p>
</li>
<li><p>React Router 5 Course</p>
</li>
<li><p>Mastering Modern JavaScript Ebook</p>
</li>
<li><p>130+ Tips, Tricks &amp; Resources Ebook</p>
</li>
</ul>
<p>👉 <a target="_blank" href="https://courses.yogeshchavan.dev/all-courses-and-ebooks">Grab This Deal Now</a></p>
<h1 id="heading-why-choose-this-offer"><strong>🎉 Why Choose This Offer?</strong></h1>
<ul>
<li><p>Pay Once, Access Forever: No monthly or yearly subscriptions.</p>
</li>
<li><p>Future-Proof: Get lifetime access to all current and upcoming content.</p>
</li>
</ul>
<h1 id="heading-coming-soon-nextjs-15-masterclass"><strong>📚 Coming Soon: Next.js 15 Masterclass!</strong></h1>
<p>Releasing 1st December 2024, this course will help you master Next.js 15 with hands-on projects:</p>
<h2 id="heading-1-event-management-app"><strong>1️⃣ Event Management App</strong></h2>
<p>Key Features:</p>
<ul>
<li><p>🔐 NextAuth v5: Secure login.</p>
</li>
<li><p>🗂️ Prisma ORM: Database operations with PostgreSQL.</p>
</li>
<li><p>🎟️ Event Workflows: Seamlessly manage events.<br />  👉 <a target="_blank" href="https://www.youtube.com/watch?v=LQ1JCEYxPfY">Watch the Preview</a></p>
</li>
</ul>
<h2 id="heading-2-online-quiz-management-system"><strong>2️⃣ Online Quiz Management System</strong></h2>
<p>Key Features:</p>
<ul>
<li><p>🧠 Dynamic topic-based quizzes.</p>
</li>
<li><p>⏱️ Timers, progress tracking, and post-quiz insights.</p>
</li>
<li><p>🗒️ Quiz history and score reviews.<br />  Tech Stack: Next.js 15, MongoDB, Express.js<br />  👉 <a target="_blank" href="https://www.youtube.com/watch?v=GAWWInd5Z2k">Check the Demo</a></p>
</li>
</ul>
<h1 id="heading-act-now"><strong>🚨 Act Now!</strong></h1>
<p>This is the biggest discount of the year, and it ends today. Don’t miss out on leveling up your skills at this unbeatable price!</p>
<p>👉 <a target="_blank" href="https://courses.yogeshchavan.dev/all-courses-and-ebooks">Get Lifetime Access for $20 / ₹1600 Now</a></p>
<h1 id="heading-connect-with-me"><strong>Connect With Me</strong></h1>
<ul>
<li><p>💻 <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/">Follow on LinkedIn</a></p>
</li>
<li><p>📹 <a target="_blank" href="https://www.youtube.com/@codingmastery_dev">Subscribe on YouTube</a></p>
</li>
<li><p>🔗 <a target="_blank" href="https://github.com/myogeshchavan97">GitHub</a></p>
</li>
</ul>
<p>Black Friday Sale: 85% Off — Don’t Miss It!<br />👉 <a target="_blank" href="https://courses.yogeshchavan.dev/">Master JavaScript, React, and Node.js</a></p>
]]></content:encoded></item><item><title><![CDATA[Learn How To Build Library Management System With Charts From Scratch Using React (Video Tutorial)]]></title><description><![CDATA[https://www.youtube.com/watch?v=pzHLYs-e3eI
 
In this 1+ hour video tutorial, you will learn to build a library management system application from scratch using React, Supabase, Shadcn/ui, and React Query.
What's Included
This application includes th...]]></description><link>https://blog.yogeshchavan.dev/learn-how-to-build-library-management-system-with-charts-from-scratch-using-react-video-tutorial</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/learn-how-to-build-library-management-system-with-charts-from-scratch-using-react-video-tutorial</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Wed, 10 Jul 2024 07:09:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720594795969/fd546890-7754-4a9a-a68d-f7f0855e5a03.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=pzHLYs-e3eI">https://www.youtube.com/watch?v=pzHLYs-e3eI</a></div>
<p> </p>
<p>In this 1+ hour video tutorial, you will learn to build a <a target="_blank" href="https://www.youtube.com/watch?v=HHAr_NlsDFY">library management system</a> application from scratch using React, Supabase, Shadcn/ui, and React Query.</p>
<h2 id="heading-whats-included">What's Included</h2>
<p>This application includes the following screens:</p>
<ol>
<li><p>Dashboard - To see a list of all books with filter and pagination functionality</p>
</li>
<li><p>Add Book - A way to add a new book</p>
</li>
<li><p>Students List - To see a list of all students with filter and pagination functionality</p>
</li>
<li><p>Add Student - A way to add a new student</p>
</li>
<li><p>Issue Book - A way to assign a new book to a student (a maximum of 10 books can be issued to each student)</p>
</li>
<li><p>Return Book - A way to return an already issued book from a student</p>
</li>
<li><p>Student Analytics - A way to see a list of all books assigned to students searchable by student ID</p>
</li>
<li><p>Books Chart - A bar chart showing books assigned to students that are searchable by student ID. The chart shows how many books are issued per month and the list of books issued, on click on each bar from the bar chart</p>
</li>
<li><p>Forgot password. - A way to reset the password if ever forgotten</p>
</li>
</ol>
<h2 id="heading-technologies-used">Technologies Used</h2>
<p>For this application, we're using:</p>
<ol>
<li><p>React for building Frontend</p>
</li>
<li><p><a target="_blank" href="https://supabase.com/">Supabase</a> is a database for storage and authentication - available for free</p>
</li>
<li><p><a target="_blank" href="https://ui.shadcn.com/">Shadcn/ui</a> library which is the most popular and highly customizable component library that uses <a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a> for styling</p>
</li>
<li><p><a target="_blank" href="https://tanstack.com/query/latest">TanStack Query ( React Query )</a> - The most popular React library for implementing caching to avoid fetching data on every page visit</p>
</li>
</ol>
<blockquote>
<p>As we're using React, we don't have to worry about hosting as we can host on any hosting provider like Netlify, Vercel, AWS or any of your favorite hosting providers.</p>
</blockquote>
<p>As we're using the <a target="_blank" href="https://ui.shadcn.com/">Shadcn/ui</a> library, we can also easily customize the application to the theme or colors of our choice.</p>
<h2 id="heading-thanks-for-reading">Thanks for Reading!</h2>
<p>Want to stay up to date with regular content regarding JavaScript, React, and Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/">Follow me on LinkedIn</a>.</p>
<ul>
<li><p>My Courses: <a target="_blank" href="https://courses.yogeshchavan.dev/">https://courses.yogeshchavan.dev/</a></p>
</li>
<li><p>My Blog: <a target="_blank" href="https://blog.yogeshchavan.dev/">https://blog.yogeshchavan.dev/</a></p>
</li>
<li><p>My LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/">https://www.linkedin.com/in/yogesh-chavan97/</a></p>
</li>
<li><p>My GitHub: <a target="_blank" href="https://github.com/myogeshchavan97">https://github.com/myogeshchavan97/</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[I Built A Library Management System With Charts Using React, Supabase, Shadcn/ui And React Query]]></title><description><![CDATA[https://youtu.be/HHAr_NlsDFY
 
Check out the video above to see a demo of the library management system application built using React.
What's Included
This application includes the following screens:

Dashboard - To see a list of all books with filte...]]></description><link>https://blog.yogeshchavan.dev/i-built-a-library-management-system-with-charts-using-react-supabase-shadcnui-and-react-query</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/i-built-a-library-management-system-with-charts-using-react-supabase-shadcnui-and-react-query</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Tue, 25 Jun 2024 09:14:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719306646098/002098f7-ef3e-467e-8a62-81a50575dbc9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/HHAr_NlsDFY">https://youtu.be/HHAr_NlsDFY</a></div>
<p> </p>
<p>Check out the video above to see a demo of the library management system application built using React.</p>
<h2 id="heading-whats-included">What's Included</h2>
<p>This application includes the following screens:</p>
<ol>
<li><p>Dashboard - To see a list of all books with filter and pagination functionality</p>
</li>
<li><p>Add Book - A way to add a new book</p>
</li>
<li><p>Students List - To see a list of all students with filter and pagination functionality</p>
</li>
<li><p>Add Student - A way to add a new student</p>
</li>
<li><p>Issue Book - A way to assign a new book to a student (a maximum of 10 books can be issued to each student)</p>
</li>
<li><p>Return Book - A way to return an already issued book from a student</p>
</li>
<li><p>Student Analytics - A way to see a list of all books assigned to students searchable by student ID</p>
</li>
<li><p>Books Chart - A bar chart showing books assigned to students that are searchable by student ID. The chart shows how many books are issued per month and the list of books issued, on click on each bar from the bar chart</p>
</li>
<li><p>Forgot password. - A way to reset the password if ever forgotten</p>
</li>
</ol>
<h2 id="heading-technologies-used">Technologies Used</h2>
<p>For this application, we're using:</p>
<ol>
<li><p>React for building Frontend</p>
</li>
<li><p><a target="_blank" href="https://supabase.com/">Supabase</a> is a database for storage and authentication - available for free</p>
</li>
<li><p><a target="_blank" href="https://ui.shadcn.com/">Shadcn/ui</a> library which is the most popular and highly customizable component library that uses <a target="_blank" href="https://tailwindcss.com/">Tailwind CSS</a> for styling</p>
</li>
<li><p><a target="_blank" href="https://tanstack.com/query/latest">TanStack Query ( React Query )</a> - The most popular React library for implementing caching to avoid fetching data on every page visit</p>
</li>
</ol>
<blockquote>
<p>As we're using React, we don't have to worry about hosting as we can host on any hosting provider like Netlify, Vercel, AWS or any of your favorite hosting providers.</p>
</blockquote>
<p>As we're using the <a target="_blank" href="https://ui.shadcn.com/">Shadcn/ui</a> library, we can also easily customize the application to the theme or colors of our choice.</p>
<h2 id="heading-thanks-for-reading">Thanks for Reading!</h2>
<p><strong>Want to learn more about the application or want to see a live demo of the application? connect me on yogesh@yogeshchavan.dev</strong></p>
<p>Want to stay up to date with regular content regarding JavaScript, React, and Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/">Follow me on LinkedIn</a>.</p>
<ul>
<li><p>My Courses: <a target="_blank" href="https://courses.yogeshchavan.dev/">https://courses.yogeshchavan.dev/</a></p>
</li>
<li><p>My Blog: <a target="_blank" href="https://blog.yogeshchavan.dev/">https://blog.yogeshchavan.dev/</a></p>
</li>
<li><p>My LinkedIn: <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/">https://www.linkedin.com/in/yogesh-chavan97/</a></p>
</li>
<li><p>My GitHub: <a target="_blank" href="https://github.com/myogeshchavan97">https://github.com/myogeshchavan97/</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to Debug Node.js Applications Using the debugger; Statement - Easiest Way]]></title><description><![CDATA[In this tutorial, you will learn the easiest and most efficient way to debug Node.js application code.
So let's get started.
Want to watch the video version of this tutorial? You can check out the video below:
https://www.youtube.com/watch?v=B_oPWQ9W...]]></description><link>https://blog.yogeshchavan.dev/how-to-debug-nodejs-applications-using-the-debugger-statement-easiest-way</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/how-to-debug-nodejs-applications-using-the-debugger-statement-easiest-way</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Tue, 30 Apr 2024 06:53:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713617407592/b690bc1f-0600-4c75-beaa-0e8de4ecf24f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, you will learn the easiest and most efficient way to debug Node.js application code.</p>
<p>So let's get started.</p>
<p>Want to watch the video version of this tutorial? You can check out the video below:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=B_oPWQ9Wyew">https://www.youtube.com/watch?v=B_oPWQ9Wyew</a></div>
<p> </p>
<h2 id="heading-how-we-usually-debug-nodejs-application">How We Usually Debug Node.js Application</h2>
<p>If we want to debug any Node.js application, usually we add a <code>console.log</code> statement in the code that we want to debug to find out the value of any variable.</p>
<p>It works but you need to keep checking the console log to see the value that you're trying to print.</p>
<p>But If the data printed in the console contains nested objects or if it's a lot of data then using <code>console.log</code> is not feasible.</p>
<p>So there is a better way.</p>
<h2 id="heading-adding-debugger-to-debug-the-code">Adding Debugger To Debug The Code</h2>
<p>Instead, we can add a <code>debugger;</code> statement in the code that we want to debug.</p>
<p>So let's say we have an Express.js API route for registering a user as shown in the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// controllers/auth.js</span>

<span class="hljs-keyword">const</span> register = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { email, password } = req.body;
    <span class="hljs-keyword">const</span> existingUser = <span class="hljs-keyword">await</span> User.findOne({
      email,
    });
    <span class="hljs-keyword">if</span> (existingUser) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">'User with the provided email already exist'</span>);
    }
    <span class="hljs-comment">// some more code</span>
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">201</span>).send();
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
    <span class="hljs-keyword">return</span> res
      .status(<span class="hljs-number">500</span>)
      .send(<span class="hljs-string">'Error while registering a new user. Try again later.'</span>);
  }
};

<span class="hljs-built_in">module</span>.exports = { register };

<span class="hljs-comment">// routes/auth.js</span>
<span class="hljs-keyword">const</span> { register } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../controllers/auth'</span>);

<span class="hljs-keyword">const</span> Router = express.Router();

Router.post(<span class="hljs-string">'/api/register'</span>, register);
</code></pre>
<p>And there is some issue while registering a user so we want to debug the <code>register</code> function code.</p>
<p>In that case, you can just add a <code>debugger;</code> statement inside the <code>register</code> function code like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> register = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { email, password } = req.body;
    <span class="hljs-keyword">debugger</span>;
    <span class="hljs-keyword">const</span> existingUser = <span class="hljs-keyword">await</span> User.findOne({
      email,
    });
    <span class="hljs-keyword">if</span> (existingUser) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">'User with the provided email already exist'</span>);
    }
    <span class="hljs-comment">// some more code</span>
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">201</span>).send();
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
    <span class="hljs-keyword">return</span> res
      .status(<span class="hljs-number">500</span>)
      .send(<span class="hljs-string">'Error while registering a new user. Try again later.'</span>);
  }
};
</code></pre>
<h2 id="heading-how-to-run-the-application-for-debugging">How To Run The Application For Debugging</h2>
<p>Normally, we start our Node.js application by executing the following command:</p>
<pre><code class="lang-javascript">node index.js
</code></pre>
<p>but instead, you can execute the following command:</p>
<pre><code class="lang-javascript">node inspect index.js
</code></pre>
<p>Here, we just added an <code>inspect</code> keyword in between.</p>
<blockquote>
<p>If your main application file name is <code>server.js</code> you can execute <code>node inspect server.js</code> command</p>
</blockquote>
<p>Once you execute the above command, you will see the output displayed as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713609952734/f916f875-33e1-4d54-b92d-24cfa017c0e8.png" alt="Starting Node.js Debugger Using Inspect" class="image--center mx-auto" /></p>
<p>As you can see from the output, the debugger is attached, so now we can start debugging the code.</p>
<p>To do that, open the Chrome browser and enter <code>chrome://inspect</code> in the browser URL.</p>
<p>You will see the output as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713610163221/5bf95ac7-f360-4c0d-9ef4-3667762c4d34.png" alt="Chrome Inspect Result" class="image--center mx-auto" /></p>
<p>as we have executed <code>node inspect index.js</code> command to start inspecting, you can see a new target entry displayed under the <code>Remote Target</code> section.</p>
<p>Now, If you click on the displayed blue <code>inspect</code> link, then you will see a new browser dev tool opened as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713610476678/785acdbf-7a05-4fea-b0d6-b876df9325f4.png" alt class="image--center mx-auto" /></p>
<p>As you can see in the right panel in the above image, <code>Debugger paused</code> message is displayed, and the debugging control is at the first line of code as you can see from the highlighted yellow line.</p>
<p>But we don't want to start debugging from the first line of code, instead, we want to just debug the registration code, so click on the blue triangle icon which is displayed just above the <code>Debugger paused</code> message as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713610809816/63f5e9de-bb68-4997-81e7-4512d65ae870.gif" alt class="image--center mx-auto" /></p>
<p>Now don't close this window, instead try registering a user from the application or by making an API call using Postman, so the <code>/register</code> route handler code that we added previously will be executed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713611715327/e82bfcb6-61aa-4737-b525-9bc9333c5dfc.gif" alt class="image--center mx-auto" /></p>
<p>As you can see above, when we click on create new account button, we're automatically redirected to the code where we added the <code>debugger;</code> statement.</p>
<p>Now, we can debug the code line by line and see the values of each variable during debugging to find out and fix the issue.</p>
<h2 id="heading-accessing-variables-during-debugging">Accessing Variables During Debugging</h2>
<p>Sometimes when we mouse over any variable while debugging to see its actual value, the value might be too long because it might be an object with many properties, so we can't see it easily by doing mouseover.</p>
<p>In that case, while the debugger is still active, we can open the console tab and type the name of the variable whose value we want to see as you can see in the below Gif:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713612358773/144e3ea6-bbb2-45d1-948f-5405ceb22e60.gif" alt class="image--center mx-auto" /></p>
<p>So that's how we can easily debug any of the Node.js application code.</p>
<h2 id="heading-creating-script-to-debug">Creating Script To Debug</h2>
<p>If you don't want to manually type the <code>node inspect index.js</code> command every time in the terminal, you can create a new <code>debug</code> script inside the <code>package.json</code> file like this:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"node index.js"</span>,
    <span class="hljs-string">"debug"</span>: <span class="hljs-string">"node inspect index.js"</span>,
    <span class="hljs-string">"dev"</span>: <span class="hljs-string">"nodemon index.js"</span>
},
</code></pre>
<p>So now, you can execute <code>npm run debug</code> command to start your application in debug mode.</p>
<h2 id="heading-quick-recap">Quick Recap</h2>
<p>To debug a Node.js application, you need to follow the below steps:</p>
<ul>
<li><p>Add a <code>debugger</code> statement inside the code that you want to debug</p>
</li>
<li><p>Run <code>node inspect index.js</code> or <code>node inspect server.js</code> command to start the application in debug mode</p>
</li>
<li><p>Access the URL <code>chrome://inspect</code> in your Chrome browser</p>
</li>
<li><p>Click on the <code>inspect</code> link under the <code>Remote Target</code> section</p>
</li>
<li><p>Click on the blue triangle icon to skip debugging, If you don't want to start debugging your application from the first line of <code>index.js</code> or <code>server.js</code> file</p>
</li>
<li><p>Make an API call or do something that will trigger the code, where you added the <code>debugger;</code> statement</p>
</li>
<li><p>This way you can debug the code line by line and find out the issue</p>
</li>
</ul>
<h2 id="heading-thanks-for-reading"><strong>Thanks for Reading</strong></h2>
<p>That's it for this tutorial. I hope you learned something new.</p>
<p>Want to watch the video version of this tutorial? You can check out <a target="_blank" href="https://www.youtube.com/watch?v=B_oPWQ9Wyew">this video.</a></p>
<p>If you want to master JavaScript, ES6+, React, and Node.js with easy-to-understand content, check out my <a target="_blank" href="https://www.youtube.com/@codingmastery_dev/">YouTube channel</a>. Don't forget to subscribe.</p>
<p>Want to stay up to date with regular content on JavaScript, React, and Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/">Follow me on LinkedIn</a>.</p>
<p><a target="_blank" href="https://www.youtube.com/watch?v=wcjCsMRZKxs"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1713614300163/0c5bd4bd-7de3-4358-80df-0322c5945b55.png" alt="Build Full Stack Link Sharing App Using MERN Stack" class="image--center mx-auto" /></a></p>
]]></content:encoded></item><item><title><![CDATA[Build & Deploy Full Stack Link Sharing App Using MERN Stack]]></title><description><![CDATA[https://www.youtube.com/watch?v=wcjCsMRZKxs
 
In this 6+ hours video course, you will learn the basics of MERN Stack From Scratch and then build and deploy a complete full-stack Link sharing App.
In this MERN Stack course, you will learn:
✅ how to im...]]></description><link>https://blog.yogeshchavan.dev/build-deploy-full-stack-link-sharing-app-using-mern-stack</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/build-deploy-full-stack-link-sharing-app-using-mern-stack</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[MERN Stack]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Thu, 18 Apr 2024 04:40:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713415059788/d4c6b650-72b5-4fe3-9eb1-7109c835a4b7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=wcjCsMRZKxs">https://www.youtube.com/watch?v=wcjCsMRZKxs</a></div>
<p> </p>
<p>In this 6+ hours video course, you will learn the basics of MERN Stack From Scratch and then build and deploy a complete full-stack Link sharing App.</p>
<p>In this MERN Stack course, you will learn:</p>
<p>✅ how to implement secure cookie-based authentication<br />✅ how to use redux toolkit for managing application state<br />✅ how to allow uploading image of specific dimension and type<br />✅ how to upload images to <a target="_blank" href="https://cloudinary.com/">Cloudinary</a><br />✅ how to create protected routes<br />✅ how to implement copy to clipboard functionality<br />✅ how to implement lazy loading in react<br />✅ how to use react context API to share data between components<br />✅ how to maintain logged in user session<br />✅ how to implement smooth animation with drag-and-drop functionality<br />✅ how to add skeleton loading effect<br />✅ how to properly display backend unhandled errors on frontend<br />✅ how to deploy this fullstack application on production</p>
<p>and much more...</p>
<h2 id="heading-thanks-for-reading"><strong>Thanks for Reading!</strong></h2>
<p>If you want to master JavaScript, ES6+, React and Node.js with easy-to-understand content, do check out my <a target="_blank" href="https://www.youtube.com/@codingmastery_dev/"><strong>YouTube channel</strong></a> and don't forget to subscribe.</p>
<p>Want to stay up to date with regular content regarding JavaScript, React, Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/"><strong>Follow me on LinkedIn</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Access My Paid React Course for FREE for LIFETIME😍]]></title><description><![CDATA[I'm thrilled to offer my paid React course for FREE!
The following are some of the reasons for making the course FREE.
✅ The ongoing layoffs and to support professionals in upskilling during these challenging times
✅ Received numerous messages reques...]]></description><link>https://blog.yogeshchavan.dev/access-my-paid-react-course-for-free-for-lifetime</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/access-my-paid-react-course-for-free-for-lifetime</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[#codenewbies]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Sun, 18 Feb 2024 05:10:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1708232554624/08140bbe-bd8e-4132-8504-7bbe13787708.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I'm thrilled to offer my paid React course for FREE!</p>
<p>The following are some of the reasons for making the course FREE.</p>
<p>✅ The ongoing layoffs and to support professionals in upskilling during these challenging times</p>
<p>✅ Received numerous messages requesting a reduction in the course price, as it was not affordable for many students</p>
<p>Now you can access my high-quality React course content and master React for FREE.</p>
<p>I have uploaded my entire React course content on my <a target="_blank" href="https://www.youtube.com/@codingmastery_dev">YouTube channel</a> in a <a target="_blank" href="https://www.youtube.com/playlist?list=PLSJnlFr3D-mHkORPbrYEhn3mEU38FerT9">new playlist</a>.</p>
<p>In this course, you will learn React from scratch and you will be building a total of 6 applications including 4 challenge Applications to get hands-on experience with React.</p>
<p>In this course, you will learn React from scratch and you will be building a total of 6 applications including 4 challenge Applications to get hands-on experience with React.</p>
<blockquote>
<p>If you have any query/doubt while going through the course, you can join the discord link from the from the description of the video and get your doubt cleared.</p>
</blockquote>
<p>𝗡𝗼𝘁𝗲: If you need a course certificate, you need to enroll in my paid React course, as the course completion progress cannot be tracked on YouTube. (At just <strong>$10</strong> instead of the previous <strong>$13</strong> price)  </p>
<p>Your money is not wasted for those who have already purchased the course.  </p>
<p>I will soon be uploading many new sections including a section exclusively in my paid React course about Testing React applications using Jest + React Testing Library.</p>
<p><strong>Access the React course for FREE by clicking</strong> <a target="_blank" href="https://www.youtube.com/playlist?list=PLSJnlFr3D-mHkORPbrYEhn3mEU38FerT9"><strong>this link</strong></a><strong>.</strong></p>
<h2 id="heading-thanks-for-reading"><strong>Thanks for Reading!</strong></h2>
<p>If you want to master JavaScript, ES6+, React and Node.js with easy-to-understand content, do check out my <a target="_blank" href="https://www.youtube.com/@codingmastery_dev/"><strong>YouTube channel</strong></a> and don't forget to subscribe.</p>
<p>Want to stay up to date with regular content regarding JavaScript, React, Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/"><strong>Follow me on LinkedIn</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[🔥Build A Movie Search App Using Redux Toolkit And React Router 6🔥]]></title><description><![CDATA[https://www.youtube.com/watch?v=TrGfZPoJNAg
 
In this 2 hour video, you will learn:  
✅ How to use TMDB API to fetch the list of movies by search keyword  
✅ How to mock API to avoid facing rate limiting issue  
✅ How to use Debouncing to avoid extra...]]></description><link>https://blog.yogeshchavan.dev/build-a-movie-search-app-using-redux-toolkit-and-react-router-6</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/build-a-movie-search-app-using-redux-toolkit-and-react-router-6</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[#codenewbies]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Sun, 28 Jan 2024 07:14:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706426071270/f8031666-0714-46fb-8944-c3ede1e9f3a4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=TrGfZPoJNAg">https://www.youtube.com/watch?v=TrGfZPoJNAg</a></div>
<p> </p>
<p>In this 2 hour video, you will learn:  </p>
<p>✅ How to use TMDB API to fetch the list of movies by search keyword  </p>
<p>✅ How to mock API to avoid facing rate limiting issue  </p>
<p>✅ How to use Debouncing to avoid extra API calls  </p>
<p>✅ How to properly display the movies list on the screen  </p>
<p>✅ How to implement routing to display movie details page when clicked on the individual movie  </p>
<p>✅ How to debug application in various scenarios  </p>
<p>✅ How to do data manipulation to get the response in the correct format using array map, filter and reduce method  </p>
<p>and much more...</p>
<p><strong>This video is the final challenge video to practice React skills from my React course:</strong> <a target="_blank" href="https://www.youtube.com/redirect?event=video_description&amp;redir_token=QUFFLUhqbXcxMEFubjFCblZ4d3k1Yk10bGpicGNXdzhwd3xBQ3Jtc0ttVVBHcGRMTk9vcTJSYURXVXpkbzdTdTBxVVhoNjJlSlJDd3prZVNnMnBtSUZnaXFjZC00R19aam9NSG42WVlEckgwTWJsQTRLRkVNWDZmbHA4OHF3OWxQUEpTSVcxelNydHloQ2ttR1RGZlV1eDRtaw&amp;q=https%3A%2F%2Fbit.ly%2F41SosrP&amp;v=TrGfZPoJNAg"><strong>https://bit.ly/41SosrP</strong></a></p>
<h2 id="heading-thanks-for-reading"><strong>Thanks for Reading!</strong></h2>
<p>If you want to master JavaScript, ES6+, React and Node.js with easy-to-understand content, do check out my <a target="_blank" href="https://www.youtube.com/@codingmastery_dev/"><strong>YouTube channel</strong></a> and don't forget to subscribe.</p>
<p>Want to stay up to date with regular content regarding JavaScript, React, Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/"><strong>Follow me on LinkedIn</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[I Launched The Most Awaited Complete React Course]]></title><description><![CDATA[🚀 Exciting Announcement! 🚀
I'm excited to share that my most awaited and requested Learn React in 30 Days course is finally live now! 🎉💻
🌐 Course Features:
Instant Access to All Videos: No need to wait anymore! Just dive right in and start your ...]]></description><link>https://blog.yogeshchavan.dev/i-launched-the-most-awaited-complete-react-course</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/i-launched-the-most-awaited-complete-react-course</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[#codenewbies]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Sat, 13 Jan 2024 05:38:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1705123018125/6c098c18-1371-4e2d-873b-56cf6280c0eb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-exciting-announcement">🚀 Exciting Announcement! 🚀</h3>
<p>I'm excited to share that my most awaited and requested <a target="_blank" href="https://learn-react.yogeshchavan.dev/">Learn React in 30 Days</a> course is finally live now! 🎉💻</p>
<p>🌐 <strong>Course Features</strong>:</p>
<p>Instant Access to All Videos: No need to wait anymore! Just dive right in and start your React journey immediately.</p>
<p>Structured Learning Path: 30 days of well-guided learning, absolutely perfect for beginners and those who are looking forward to mastering React.</p>
<p>Hands-On Projects: Give your skills practical touch with real-world projects.</p>
<p>Don't just take my word. See what others are saying!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1705123789463/27cbc53e-aa4d-4b51-8a94-c71f0710ebf7.png" alt class="image--center mx-auto" /></p>
<p>With this course, you will also get access to my popular <a target="_blank" href="https://modernjavascript.yogeshchavan.dev/">Mastering Modern JavaScript</a> ebook for 𝗙𝗥𝗘𝗘.</p>
<p><strong>You will be writing every line of CSS yourself while building applications in this course, so you will get hands-on experience of designing web applications.</strong></p>
<p>React has become the backbone of modern web development, favored for its flexibility, efficiency, and robustness. 🌐</p>
<p><strong>With Next.js popularity, React has become a mandatory technology to get a high-salary and your dream job.</strong></p>
<p>It's the tool of choice for crafting dynamic, lightning-fast user interfaces. ⚡</p>
<p>This course isn't a mere walkthrough of React concepts. It's a deep dive into the core principles, combined with practical, hands-on learning 🛠️</p>
<p>Here's what you can expect:</p>
<p>👩‍💻 <strong>Real-World Project</strong>: It's not just theory! We'll build real-world project together, giving you the confidence and portfolio pieces to showcase your skills to potential employers or clients.</p>
<p>🚀 <strong>Performance Optimization</strong>: Learn how to write efficient code that doesn't just work but excels in terms of speed, performance, and maintainability.</p>
<p><strong>What Sets This Course Apart?🤔</strong></p>
<p>This isn't just about learning React basics but React and its associated libraries in detail with every concept explained from scratch.</p>
<p>In addition to that, you will also be learning:</p>
<p>✅ React Basic Concepts</p>
<p>✅ JSX Fundamentals</p>
<p>✅ Class components And Functional Components</p>
<p>✅ Styling React App</p>
<p>✅ Handling State and Props</p>
<p>✅ Working With Forms</p>
<p>✅ Event Handling</p>
<p>✅ React Hooks</p>
<p>✅ Custom Hooks</p>
<p>✅ How To Write Maintainable CSS</p>
<p>✅ Making Web Application Responsive</p>
<p>✅ React Context API</p>
<p>✅ Using useReducer Hook</p>
<p>✅ Handling Routing Using React Router</p>
<p>✅ <strong>How To Improve Application Performance Using Lazy Loading</strong></p>
<p>✅ Core Redux</p>
<p>✅ Redux Toolkit</p>
<p>✅ <strong>Many Videos Showing Debugging In Various Scenarios</strong></p>
<p>✅ <strong>How To Write Code Like A Senior React Developer</strong></p>
<p>✅ Coding Tips And Best Practices</p>
<p>and a lot more. 🎓💡</p>
<p>Get Access to the Discord community to get your doubts cleared.</p>
<p><strong>🏆 You will also get a course completion certificate that validates your expertise in React development, a valuable asset in your portfolio.</strong></p>
<p>As a part of the launch offer, get the course at just <strong>$8 / ₹640</strong> instead of the regular price of <strong>$13 / ₹1040</strong>.</p>
<p><strong>This discount is valid only till 15th January.</strong></p>
<p>🎓 Who's it for?</p>
<p>Beginners, who are extremely eager to embark on their coding journey.</p>
<p>Professionals, who are looking to level up their skills.</p>
<p>Passionate developers, who have a strong desire to become React masters.</p>
<p>Don't miss this opportunity to immensely accelerate your React skills! 🚀 Enroll right away and instantly access all the videos.</p>
<p>Let's code something truly extraordinary together! 💡💻</p>
<p><strong>📅 Course Details:</strong></p>
<p>Start Learning Today: <a target="_blank" href="https://learn-react.yogeshchavan.dev/">https://learn-react.yogeshchavan.dev/</a></p>
<h2 id="heading-thanks-for-reading"><strong>Thanks for Reading!</strong></h2>
<p>If you want to master JavaScript, ES6+, React and Node.js with easy-to-understand content, do check out my <a target="_blank" href="https://www.youtube.com/@codingmastery_dev/"><strong>YouTube channel</strong></a> and don't forget to subscribe.</p>
<p>Want to stay up to date with regular content regarding JavaScript, React, Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/"><strong>Follow me on LinkedIn</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Introduction to TypeScript with React]]></title><description><![CDATA[In this article, you will learn how to use TypeScript with React.
So by the end of this article, you will have a solid understanding of how to write React code with TypeScript.
Want to watch the video version of this tutorial? You can check out the v...]]></description><link>https://blog.yogeshchavan.dev/introduction-to-typescript-with-react</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/introduction-to-typescript-with-react</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Sun, 26 Nov 2023 05:54:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1700977957185/2160876f-6c50-421b-8a98-56b2dfce5ae3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, you will learn how to use TypeScript with React.</p>
<p>So by the end of this article, you will have a solid understanding of how to write React code with TypeScript.</p>
<p>Want to watch the video version of this tutorial? You can check out the video below:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=KmYoJmZs3sY">https://www.youtube.com/watch?v=KmYoJmZs3sY</a></div>
<p> </p>
<p><a target="_blank" href="https://courses.yogeshchavan.dev/build-expense-manager-app-using-react-and-typescript"><img src="https://www.freecodecamp.org/news/content/images/2023/11/expense_manager_app_banner.png" alt /></a></p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this tutorial, there are some prerequisites. You should:</p>
<ul>
<li><p>Have basic knowledge of working with React</p>
</li>
<li><p>Basic understanding of writing TypeScript code</p>
</li>
</ul>
<h2 id="heading-getting-started"><strong>Getting Started</strong></h2>
<p>To get started with TypeScript, you first need to install TypeScript on your machine which you can do by executing <code>npm install -g typescript</code> from the terminal or command prompt.</p>
<p>Now, we will create a <a target="_blank" href="https://vitejs.dev/">Vite</a> project using TypeScript.</p>
<pre><code class="lang-js">npm create vite
</code></pre>
<p>Once executed, you will be asked some questions.</p>
<p>For the project name, enter <code>react-typescript-demo</code>.</p>
<p>For framework, select <code>React</code> and for variant select <code>TypeScript</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699942833707/8978648a-b518-4ae5-ba66-71c24e57aecb.png" alt class="image--center mx-auto" /></p>
<p>Once the project is created, open the project in VS Code and execute the following commands from the terminal:</p>
<pre><code class="lang-javascript">cd react-typescript-demo
npm install
</code></pre>
<p>Now, let's do some code cleanup.</p>
<p>Remove the <code>src/App.css</code> file and replace the content of <code>src/App.tsx</code> file with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>After saving the file, you might see the red underlines in the file as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699943454193/6946ebf2-d619-4b0d-8589-f6f837c6d949.png" alt class="image--center mx-auto" /></p>
<p>If you get that error, just press <code>Cmd + Shift + P(Mac)</code> or <code>Ctrl + Shift + P(Windows/Linux)</code>to open the VS Code command palette and enter <code>TypeScript</code> text in the search box and select the option <code>TypeScript: Select TypeScript Version...</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699943609248/9a95a672-2ea6-4d7c-9bf6-eac83b41d8f0.png" alt class="image--center mx-auto" /></p>
<p>Once selected, you will see options to select between the VS Code version and the workspace version as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699943698346/250df0c1-ce0c-4f51-bc97-4ded04cf6392.png" alt class="image--center mx-auto" /></p>
<p>From these options, you need to select <code>Use Workspace Version</code> option and once you select that option, the error from the <code>App.tsx</code> file will be gone.</p>
<p>Now, open <code>src/index.css</code> file and replace its contents with the following content:</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">font-family</span>: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1.5</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">400</span>;

  <span class="hljs-attribute">font-synthesis</span>: none;
  <span class="hljs-attribute">text-rendering</span>: optimizeLegibility;
  <span class="hljs-attribute">-webkit-font-smoothing</span>: antialiased;
  <span class="hljs-attribute">-moz-osx-font-smoothing</span>: grayscale;
  <span class="hljs-attribute">-webkit-text-size-adjust</span>: <span class="hljs-number">100%</span>;
}
</code></pre>
<p>Now, let's start the application, by executing <code>npm run dev</code> command.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699943914501/194c4357-1852-4803-946b-df2cd621360d.png" alt class="image--center mx-auto" /></p>
<p>Now, click on the displayed URL and access the application, you will see the following initial screen with text <code>App</code> displayed in the browser.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699944017441/701358b4-4bdc-49de-b008-245ef71fc929.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-react-and-typescript-basics"><strong>React and TypeScript Basics</strong></h2>
<p>When using React with TypeScript, the first thing you should know is the file extension.</p>
<p>Every React + TypesSript file needs to have a <code>.tsx</code> extension.</p>
<p>If the file does not contain any JSX-specific code, then you can use the <code>.ts</code> extension instead of the <code>.tsx</code> extension.</p>
<p>To create a component in React with TypeScript, you can use the <code>FC</code> type from the <code>react</code> package and use it after the component name.</p>
<p>So open <code>src/App.tsx</code> file and replace it with the following contents:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { FC } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> App: FC = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now, let's pass some props to this <code>App</code> component.</p>
<p>Open <code>src/main.tsx</code> and pass a <code>title</code> prop to the <code>App</code> component as shown below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.tsx'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)!).render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> <span class="hljs-attr">title</span>=<span class="hljs-string">'TypeScript Demo'</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>
);
</code></pre>
<p>However, with the added <code>title</code> prop, we now have a TypeScript error as you can see below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699949857156/aa582428-63cb-4bc0-a4c3-02ac13fe588f.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-three-ways-of-defining-prop-types"><strong>Three Ways of Defining Prop Types</strong></h2>
<p>We can fix the above TypeScript error in three different ways.</p>
<ul>
<li>Declaring Types Using Interface</li>
</ul>
<p>The error is coming because we have added a <code>title</code> prop as a mandatory prop for the <code>App</code> component so we need to mention this inside the <code>App</code> component.</p>
<p>So open <code>src/App.tsx</code> file and replace its contents with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { FC } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

interface AppProps {
  <span class="hljs-attr">title</span>: string;
}

<span class="hljs-keyword">const</span> App: FC&lt;AppProps&gt; = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>As you can see above, we have added an extra interface <code>AppProps</code> to specify which props the component is accepting and we used the <code>AppProps</code> interface after the <code>FC</code> in angle brackets.</p>
<blockquote>
<p>It's a good practice and recommended to start the interface name with a capital letter like <code>AppProps</code> in our case.</p>
</blockquote>
<p>Now, with this change, the TypeScript error will be gone as you can see below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699951830147/5d51e7d5-1854-418c-9b12-1e5b916fae99.gif" alt class="image--center mx-auto" /></p>
<p>This is how we specify what props a particular component accepts.</p>
<ul>
<li>Declaring Types Using type</li>
</ul>
<p>We can also declare the props type using <code>type</code> keyword.</p>
<p>So open <code>App.tsx</code> file and change the below code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { FC } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

interface AppProps {
  <span class="hljs-attr">title</span>: string;
}

<span class="hljs-keyword">const</span> App: FC&lt;AppProps&gt; = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>to this code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { FC } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

type AppProps = {
  <span class="hljs-attr">title</span>: string;
};

<span class="hljs-keyword">const</span> App: FC&lt;AppProps&gt; = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here, instead of <code>interface</code> declaration we used <code>type</code> declaration and the code will work without any TypeScript error.</p>
<p>It's up to you, which way to use, I always like to use an interface for declaring component types.</p>
<ul>
<li>Using inline type declaration</li>
</ul>
<p>The third way of declaring type is by defining inline types as shown below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> App = <span class="hljs-function">(<span class="hljs-params">{ title }: { title: string }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>App<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>As you can see above, we have removed the use of <code>FC</code> as it's not needed, and while destructuring the <code>title</code> prop we defined the type of it.</p>
<p>So out of these three ways, you can use whichever way you want. I always prefer to use an interface with <code>FC</code> so if later I want to add more props, the code will not look complicated which will happen if you define inline types.</p>
<p>Now, let's use the <code>title</code> prop and display it on the UI.</p>
<p>Now, replace the contents of the <code>App.tsx</code> file with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { FC } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

interface AppProps {
  <span class="hljs-attr">title</span>: string;
}

<span class="hljs-keyword">const</span> App: FC&lt;AppProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ title }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>As you can see, we're using an interface with <code>FC</code> and we're destructuring the <code>title</code> prop and displaying it on the screen.</p>
<p>Now, open <code>src/index.css</code> file and add the following CSS inside it:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">text-align</span>: center;
}
</code></pre>
<p>If you check the application in the browser, you will see that the title with text <code>TypeScript Demo</code> is correctly getting displayed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699953876059/8bc4487d-111d-4c5e-8a0c-8df81d969db2.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-how-to-create-a-random-users-list-application"><strong>How to Create a Random Users List Application</strong></h2>
<p>Now, that you have a basic idea of how to declare component props, let's create a simple Random Users List Application that will display a list of 10 random users on the screen.</p>
<p>For that, we will be using <a target="_blank" href="https://randomuser.me/">Random User Generator</a> API.</p>
<p>And the API URL we will be using is this:</p>
<pre><code class="lang-javascript">https:<span class="hljs-comment">//randomuser.me/api/?results=10</span>
</code></pre>
<p>So let's first install the <a target="_blank" href="https://www.npmjs.com/package/axios">axios</a> npm library, so we can make an API call using it.</p>
<p>Execute the following command to install the axios library:</p>
<pre><code class="lang-javascript">npm install axios
</code></pre>
<p>Once installed, restart the application by executing <code>npm run dev</code> command.</p>
<p>Now, replace the contents of <code>App.tsx</code> file with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> { FC, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

interface AppProps {
  <span class="hljs-attr">title</span>: string;
}

<span class="hljs-keyword">const</span> App: FC&lt;AppProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ title }</span>) =&gt;</span> {
  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> getUsers = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
          <span class="hljs-string">'https://randomuser.me/api/?results=10'</span>
        );
        <span class="hljs-built_in">console</span>.log(data);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(error);
      }
    };
    getUsers();
  }, []);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>As you can see above, we have added an <code>useEffect</code> hook where we're making API call to get the the list of users.</p>
<p>Now, If you open the console in the browser, you will be able to see the API response displayed in the console.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699958615301/f09c1e72-0a79-4c13-aa61-2428e9cd4313.png" alt class="image--center mx-auto" /></p>
<p>As you can see, we're correctly getting a list of 10 random users and the actual users list is coming in the <code>results</code> property of the response.</p>
<h2 id="heading-how-to-store-the-users-list-in-state"><strong>How to Store the Users List in State</strong></h2>
<p>Now, let's store those users in the state so we can display them on the screen.</p>
<p>So inside the <code>App</code> component, declare a new state with an initial value of an empty array like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [users, setUsers ] = useState([]);
</code></pre>
<p>And call the <code>setUsers</code> function to store the users in the <code>useEffect</code> hook after the API call.</p>
<p>So your <code>App</code> component will look like this now:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> { FC, useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

interface AppProps {
  <span class="hljs-attr">title</span>: string;
}

<span class="hljs-keyword">const</span> App: FC&lt;AppProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ title }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [users, setUsers] = useState([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> getUsers = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
          <span class="hljs-string">'https://randomuser.me/api/?results=10'</span>
        );
        <span class="hljs-built_in">console</span>.log(data);
        setUsers(data.results);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(error);
      }
    };
    getUsers();
  }, []);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>As you can see here, we're calling <code>setUsers</code> function with the value of <code>data.results</code>.</p>
<h2 id="heading-how-to-display-the-users-on-the-ui"><strong>How to Display the Users on the UI</strong></h2>
<p>Now, let's display the name and email of the individual user on the screen.</p>
<p>If you check the console output, you can see that there is a <code>name</code> property for each object that contains the first and last name of the user. So we can combine them to display the complete name.</p>
<p>Also, we have a direct <code>email</code> property for each user object which we can use to display email.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699960203486/0ec262d2-c8bd-43b9-978c-168096665f5f.gif" alt class="image--center mx-auto" /></p>
<p>So replace the contents of <code>App.tsx</code> file with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> { FC, useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

interface AppProps {
  <span class="hljs-attr">title</span>: string;
}

<span class="hljs-keyword">const</span> App: FC&lt;AppProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ title }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [users, setUsers] = useState([]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> getUsers = <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
          <span class="hljs-string">'https://randomuser.me/api/?results=10'</span>
        );
        <span class="hljs-built_in">console</span>.log(data);
        setUsers(data.results);
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.log(error);
      }
    };
    getUsers();
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {users.map(({ login, name, email }) =&gt; {
          return (
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{login.uuid}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
                Name: {name.first} {name.last}
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Email: {email}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          );
        })}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>As you can see, we're using the <a target="_blank" href="https://www.youtube.com/watch?v=ffxvkWmaU7s&amp;list=PLSJnlFr3D-mGIHFpo80ylsaBErtueSpYS&amp;index=8">array map method</a> to loop over the <code>users</code> array, and we're using <a target="_blank" href="https://www.youtube.com/watch?v=3JsFklg1WhU&amp;list=PLSJnlFr3D-mGIHFpo80ylsaBErtueSpYS&amp;index=20">object destructuring</a> to destructure the <code>login</code>, <code>name</code> and <code>email</code> properties of individual <code>user</code> object, and as an un-ordered list we're displaying the name and email of the user.</p>
<p>However, you will see some TypeScript errors in the file as can be seen below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699960584435/72173126-29ac-4267-81af-33b3a382a9c3.png" alt class="image--center mx-auto" /></p>
<p>This is because, as you can see above, by default TypeScript assumes the type of <code>users</code> array to be <code>never[]</code>, so it's not able to find out which properties the <code>users</code> array contains.</p>
<p>So we specifically need to specify all of the properties that we're using along with their types.</p>
<p>Therefore, declare a new interface after the <code>AppProps</code> interface like this:</p>
<pre><code class="lang-javascript">
interface Users {
  <span class="hljs-attr">name</span>: {
    <span class="hljs-attr">first</span>: string;
    last: string;
  };
  login: {
    <span class="hljs-attr">uuid</span>: string;
  };
  email: string;
}
</code></pre>
<p>Here, we're specifying that, each individual <code>user</code> will be an object with <code>name</code>, <code>login</code> and <code>email</code> properties, and we're also specifying the data type of each property.</p>
<p>As you can see, each <code>user</code> object coming from the API has a lot of other properties like <code>phone</code>, <code>location</code> and others. But we only need to specify those properties that we're using in the code.</p>
<p>Now, change the <code>useState</code> users array declaration from this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [users, setUsers] = useState([]);
</code></pre>
<p>to this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [users, setUsers] = useState&lt;Users[]&gt;([]);
</code></pre>
<p>Here, we're specifying that <code>users</code> is an array of objects of type <code>Users</code> which is the interface we declared.</p>
<p>Now, If you check the <code>App.tsx</code> file, you will see that there are no TypeScript errors.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699967171464/eaf32715-a74d-4c21-b404-7e8e79c9eac0.png" alt class="image--center mx-auto" /></p>
<p>And you will be able to see the list of 10 random users displayed on the screen:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699967274864/cefd0d9c-5f27-46e7-8c68-b843aa39968a.png" alt class="image--center mx-auto" /></p>
<p>As you have seen previously, we have declared <code>Users</code> interface like this:</p>
<pre><code class="lang-javascript">interface Users {
  <span class="hljs-attr">name</span>: {
    <span class="hljs-attr">first</span>: string;
    last: string;
  };
  login: {
    <span class="hljs-attr">uuid</span>: string;
  };
  email: string;
}
</code></pre>
<p>However, when you have nested properties, you will see it written like this:</p>
<pre><code class="lang-javascript">interface Name {
  <span class="hljs-attr">first</span>: string;
  last: string;
}

interface Login {
  <span class="hljs-attr">uuid</span>: string;
}

interface Users {
  <span class="hljs-attr">name</span>: Name;
  login: Login;
  email: string;
}
</code></pre>
<p>The advantage of declaring separate interfaces for each nested property is that, If you want to use the same structure in any other file, you can just export any of the above interfaces and re-use in other files, Instead of re-declaring the same interface again.</p>
<p>So let's export all of the above interfaces as a <a target="_blank" href="https://www.youtube.com/watch?v=_5nxKhP9UOo&amp;list=PLSJnlFr3D-mGIHFpo80ylsaBErtueSpYS&amp;index=4">named export</a>. So the code will look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> interface Name {
  <span class="hljs-attr">first</span>: string;
  last: string;
}

<span class="hljs-keyword">export</span> interface Login {
  <span class="hljs-attr">uuid</span>: string;
}

<span class="hljs-keyword">export</span> interface Users {
  <span class="hljs-attr">name</span>: Name;
  login: Login;
  email: string;
}
</code></pre>
<p>As I said previously, you can also use type declaration here instead of using the interface, so it will look like this:</p>
<pre><code class="lang-javascript">type Name = {
  <span class="hljs-attr">first</span>: string;
  last: string;
};

type Login = {
  <span class="hljs-attr">uuid</span>: string;
};

type Users = {
  <span class="hljs-attr">name</span>: Name;
  login: Login;
  email: string;
};
</code></pre>
<h2 id="heading-how-to-create-a-separate-user-component"><strong>How to Create a Separate User Component</strong></h2>
<p>When we're using an array <code>map</code> method, to display something on the screen, it's common to separate out that display part in a different component so it's easy to test and it will also make your component code shorter.</p>
<p>So create a <code>components</code> folder inside <code>src</code> folder and create <code>User.tsx</code> file inside it and add the following contents inside it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> User = <span class="hljs-function">(<span class="hljs-params">{ login, name, email }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{login.uuid}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        Name: {name.first} {name.last}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Email: {email}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> User;
</code></pre>
<p>If you save the file, you will see the TypeScript errors again.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699968969640/e4ca61d3-ac8f-4ce9-8110-df280182fe04.png" alt class="image--center mx-auto" /></p>
<p>So we again need to specify which props the <code>User</code> component will be receiving, and we also need to specify the data type of each of them.</p>
<p>So the updated <code>User.tsx</code> file will look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { FC } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Login, Name } <span class="hljs-keyword">from</span> <span class="hljs-string">'../App'</span>;

interface UserProps {
  <span class="hljs-attr">login</span>: Login;
  name: Name;
  email: string;
}

<span class="hljs-keyword">const</span> User: FC&lt;UserProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ login, name, email }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{login.uuid}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        Name: {name.first} {name.last}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Email: {email}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> User;
</code></pre>
<p>As you can see above, we have declared a <code>UserProps</code> interface above and we have specified it for the <code>User</code> component using <code>FC</code>.</p>
<p>Also, note that we're not declaring the data type of <code>name</code> and <code>login</code> properties, instead we're using the exported types from <code>App.tsx</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Login, Name } <span class="hljs-keyword">from</span> <span class="hljs-string">'../App'</span>;
</code></pre>
<p>That's why it's good to declare separate types for each nested property, so we can reuse it elsewhere.</p>
<p>Now, we can use this <code>User</code> component inside the <code>App.tsx</code> file.</p>
<p>So change the below code:</p>
<pre><code class="lang-javascript">{users.map(<span class="hljs-function">(<span class="hljs-params">{ login, name, email }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{login.uuid}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        Name: {name.first} {name.last}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Email: {email}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
})}
</code></pre>
<p>to this code:</p>
<pre><code class="lang-javascript">{users.map(<span class="hljs-function">(<span class="hljs-params">{ login, name, email }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">User</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{login.uuid}</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{name}</span> <span class="hljs-attr">email</span>=<span class="hljs-string">{email}</span> /&gt;</span></span>;
})}
</code></pre>
<p>As you might know when using the array <code>map</code> method, we need to provide the <code>key</code> for the parent element which is <code>User</code> in our case so we have added <code>key</code> prop while using the <code>User</code> component as shown above.</p>
<p>So that means we don't need key inside the <code>User</code> component, so we can remove the <code>key</code> and <code>login</code> prop from the <code>User</code> component.</p>
<p>So the updated <code>User</code> component will look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { FC } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Name } <span class="hljs-keyword">from</span> <span class="hljs-string">'../App'</span>;

interface UserProps {
  <span class="hljs-attr">name</span>: Name;
  email: string;
}

<span class="hljs-keyword">const</span> User: FC&lt;UserProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ name, email }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        Name: {name.first} {name.last}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Email: {email}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> User;
</code></pre>
<p>As you can see we have removed the <code>login</code> prop from the interface and also while destructuring it and the application is still working as before without any issues as you can see below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699971331194/ec33f382-0b46-4d40-9c8e-5ec50bc051eb.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-how-to-create-a-separate-file-for-type-declarations"><strong>How to Create a Separate File for Type Declarations</strong></h2>
<p>As you can see, the <code>App.tsx</code> file has become quite large because of the interface declarations, so it's common to have a separate file just for declaring types.</p>
<p>So create a <code>App.types.ts</code> file inside the <code>src</code> folder and move all the type declarations from <code>App</code> component to <code>App.types.ts</code> file:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> AppProps {
  title: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Name {
  first: <span class="hljs-built_in">string</span>;
  last: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Login {
  uuid: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> Users {
  name: Name;
  login: Login;
  email: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>Note that, we're also exporting the <code>AppProps</code> component in the above code.</p>
<p>Now, update the <code>App.tsx</code> file to use these types as shown below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> { FC, useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { AppProps, Users } <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.types'</span>;
<span class="hljs-keyword">import</span> User <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/User'</span>;

<span class="hljs-keyword">const</span> App: FC&lt;AppProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ title }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [users, setUsers] = useState&lt;Users[]&gt;([]);

  <span class="hljs-comment">// ...</span>
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>As you can see above, we're importing the <code>AppProps</code> and <code>Users</code> from <code>App.types</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { AppProps, Users } <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.types'</span>;
</code></pre>
<p>And your <code>User.tsx</code> file will look like this now:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { FC } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Name } <span class="hljs-keyword">from</span> <span class="hljs-string">'../App.types'</span>;

interface UserProps {
  <span class="hljs-attr">name</span>: Name;
  email: string;
}

<span class="hljs-keyword">const</span> User: FC&lt;UserProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ name, email }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        Name: {name.first} {name.last}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Email: {email}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> User;
</code></pre>
<p>As you can see above, we're importing the <code>Name</code> from <code>App.types</code> file.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Name } <span class="hljs-keyword">from</span> <span class="hljs-string">'../App.types'</span>;
</code></pre>
<h2 id="heading-how-to-display-a-loading-indicator"><strong>How to Display a Loading Indicator</strong></h2>
<p>Whenever you're making an API call to display something, it's always good to display some loading indicator, while the API call is going on.</p>
<p>So let's add a new <code>isLoading</code> state inside the <code>App</code> component:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<p>As you can see, we have not mentioned any data type while declaring a state like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState&lt;boolean&gt;(<span class="hljs-literal">false</span>);
</code></pre>
<p>This is because when we assign any initial value, <code>false</code> in our case, TypeScript automatically infers the type of data we will be storing which is <code>boolean</code> in our case.</p>
<p>When we declared <code>users</code> state, it was not clear what we would be storing by just the initial value of an empty array <code>[]</code> so we needed to mention its type like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [users, setUsers] = useState&lt;Users[]&gt;([]);
</code></pre>
<p>Now, change the <code>useEffect</code> code to the below code:</p>
<pre><code class="lang-javascript">useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> getUsers = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      setIsLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
        <span class="hljs-string">'https://randomuser.me/api/?results=10'</span>
      );
      <span class="hljs-built_in">console</span>.log(data);
      setUsers(data.results);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
    } <span class="hljs-keyword">finally</span> {
      setIsLoading(<span class="hljs-literal">false</span>);
    }
  };
  getUsers();
}, []);
</code></pre>
<p>Here, we're calling <code>setIsLoading</code> with value of <code>true</code> before the API call, and inside the <code>finally</code> block, we're setting it back to <code>false</code>.</p>
<p>The code written inside the <code>finally</code> block will always execute even if there is success or failure. So even if the API call succeeds or fails, we need to hide the loading message so we're using <code>finally</code> block to achieve that.</p>
<p>Now, we can use the <code>isLoading</code> state value to display a loading message on the screen.</p>
<p>After the <code>h1</code> tag and before the <code>ul</code> tag, add the following code:</p>
<pre><code class="lang-javascript">{isLoading &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>}
</code></pre>
<p>Now, If you check the application, you will be able to see the loading message while the list of users is getting loaded.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699974992118/800d97ce-22cc-420f-97cc-cec2b20032b7.gif" alt class="image--center mx-auto" /></p>
<p>So this is a better user experience.</p>
<p>However, If you keep a closer look at the displayed users, you will see that the users are getting changed once loaded.</p>
<p>So initially we see a set of 10 random users and immediately we see a different set of random users without reloading the page.</p>
<p>This is because we're using React version 18(which you can verify from <code>package.json</code> file) and <code>React.StrictMode</code> inside the <code>src/main.tsx</code> file.</p>
<p>And with version 18 of React, when we use <code>React.StrictMode</code>, every <code>useEffect</code> hook executes twice even with no dependency specified.</p>
<blockquote>
<p>This only happens in the development environment and not in the production when you deploy the application.</p>
</blockquote>
<p>Because of this, the API call is made twice and as the random users API returns a new set of random users every time the API is called, we're setting a different set of users to the <code>users</code> array using <code>setUsers</code> call inside the <code>useEffect</code> hook.</p>
<p>This is the reason we see users getting changed without refreshing the page.</p>
<p>If you don't want this behaviour during development, you can remove the <code>React.StrictMode</code> from the <code>main.tsx</code> file.</p>
<p>So change the below code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.tsx'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)!).render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> <span class="hljs-attr">title</span>=<span class="hljs-string">'TypeScript Demo'</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>
);
</code></pre>
<p>to this code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.tsx'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)!).render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> <span class="hljs-attr">title</span>=<span class="hljs-string">'TypeScript Demo'</span> /&gt;</span></span>
);
</code></pre>
<p>Now, If you check the application, you will see that the list of users is not getting changed, once loaded.</p>
<h2 id="heading-how-to-load-users-on-button-click"><strong>How to Load Users on Button Click</strong></h2>
<p>Now, instead of making the API call on page load, let's add a show users button and we will make the API call when we click on that button.</p>
<p>So after <code>h1</code> tag add a new button as shown below:</p>
<pre><code class="lang-javascript">&lt;button onClick={handleClick}&gt;Show Users&lt;/button&gt;
</code></pre>
<p>Now, add <code>handleClick</code> method inside the <code>App</code> component and move all the code from <code>getUsers</code> function to the <code>handleClick</code> method:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> handleClick = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    setIsLoading(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'https://randomuser.me/api/?results=10'</span>);
    <span class="hljs-built_in">console</span>.log(data);
    setUsers(data.results);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
  } <span class="hljs-keyword">finally</span> {
    setIsLoading(<span class="hljs-literal">false</span>);
  }
};
</code></pre>
<p>Now, you can remove or comment out the <code>useEffect</code> hook as it's no longer needed.</p>
<p>Your updated <code>App.tsx</code> file will look like this now:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> { FC, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { AppProps, Users } <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.types'</span>;
<span class="hljs-keyword">import</span> User <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/User'</span>;

<span class="hljs-keyword">const</span> App: FC&lt;AppProps&gt; = <span class="hljs-function">(<span class="hljs-params">{ title }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [users, setUsers] = useState&lt;Users[]&gt;([]);
  <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState&lt;boolean&gt;(<span class="hljs-literal">false</span>);

  <span class="hljs-comment">// useEffect(() =&gt; {</span>
  <span class="hljs-comment">//   const getUsers = async () =&gt; {</span>
  <span class="hljs-comment">//     try {</span>
  <span class="hljs-comment">//       setIsLoading(true);</span>
  <span class="hljs-comment">//       const { data } = await axios.get(</span>
  <span class="hljs-comment">//         'https://randomuser.me/api/?results=10'</span>
  <span class="hljs-comment">//       );</span>
  <span class="hljs-comment">//       console.log(data);</span>
  <span class="hljs-comment">//       setUsers(data.results);</span>
  <span class="hljs-comment">//     } catch (error) {</span>
  <span class="hljs-comment">//       console.log(error);</span>
  <span class="hljs-comment">//     } finally {</span>
  <span class="hljs-comment">//       setIsLoading(false);</span>
  <span class="hljs-comment">//     }</span>
  <span class="hljs-comment">//   };</span>
  <span class="hljs-comment">//   getUsers();</span>
  <span class="hljs-comment">// }, []);</span>

  <span class="hljs-keyword">const</span> handleClick = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      setIsLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(<span class="hljs-string">'https://randomuser.me/api/?results=10'</span>);
      <span class="hljs-built_in">console</span>.log(data);
      setUsers(data.results);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
    } <span class="hljs-keyword">finally</span> {
      setIsLoading(<span class="hljs-literal">false</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>{title}<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>&gt;</span>Show Users <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      {isLoading &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
        {users.map(({ login, name, email }) =&gt; {
          return <span class="hljs-tag">&lt;<span class="hljs-name">User</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{login.uuid}</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{name}</span> <span class="hljs-attr">email</span>=<span class="hljs-string">{email}</span> /&gt;</span>;
        })}
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now, If you check the application, you will see that users are loaded only when clicking on the show users button and we also see the loading message.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699983100542/a6e4541d-9c80-4838-889b-e0d1e5ca4907.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-how-to-handle-the-change-event"><strong>How to Handle the Change Event</strong></h2>
<p>Now, let's add an input field and when we type anything in that input field, we will display the entered text below that input field.</p>
<p>Add an input field after the button like this:</p>
<pre><code class="lang-javascript">&lt;input type=<span class="hljs-string">'text'</span> onChange={handleChange} /&gt;
</code></pre>
<p>And declare a new state to store the entered value like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [username, setUsername] = useState(<span class="hljs-string">''</span>);
</code></pre>
<p>Now, add a <code>handleChange</code> method inside the <code>App</code> component like this:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  setUsername(event.target.value);
};
</code></pre>
<p>However, you will see that, we're getting a TypeScript error for the event parameter.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699983655820/2d619d87-3d13-41c4-a85e-d9a18b6a2f0b.png" alt class="image--center mx-auto" /></p>
<p>With TypeScript we always need to specify the type of each and every function parameter.</p>
<p>Here, TypeScript is not able to identify what's the type of <code>event</code> parameter.</p>
<p>To find out the type of <code>event</code> parameter, we can change the below code:</p>
<pre><code class="lang-javascript">&lt;input type=<span class="hljs-string">'text'</span> onChange={handleChange} /&gt;
</code></pre>
<p>to this code:</p>
<pre><code class="lang-javascript">&lt;input type=<span class="hljs-string">'text'</span> onChange={<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {}} /&gt;
</code></pre>
<p>Here, we're using an inline function because when using inline function, the correct type is automatically passed to the function parameter so we don't need to specify it.</p>
<p>So If you mouse over the <code>event</code> parameter, you will be able to see the exact type of event that we can use in our <code>handleChange</code> function as you can see below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699984155605/fefdc012-85b6-47d0-b019-f9ee9b810a08.gif" alt class="image--center mx-auto" /></p>
<p>Now, you can revert the below code:</p>
<pre><code class="lang-javascript">&lt;input type=<span class="hljs-string">'text'</span> onChange={<span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {}} /&gt;
</code></pre>
<p>to this code:</p>
<pre><code class="lang-javascript">&lt;input type=<span class="hljs-string">'text'</span> onChange={handleChange} /&gt;
</code></pre>
<p>Now, let's display the value of <code>username</code> state variable below the input field:</p>
<pre><code class="lang-javascript">&lt;input type=<span class="hljs-string">'text'</span> onChange={handleChange} /&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{username}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p>If you check the application now, you will be able to see the entered text displayed below the input field.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1699985364920/a418c253-45ed-49a6-b321-f4855fe0e153.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-thanks-for-reading"><strong>Thanks for Reading</strong></h2>
<p>That's it for this tutorial. I hope you learned a lot from it.</p>
<p>Want to watch the video version of this tutorial? You can check out <a target="_blank" href="https://www.youtube.com/watch?v=KmYoJmZs3sY">this video.</a></p>
<p>You can find the complete source code for this application in <a target="_blank" href="https://github.com/myogeshchavan97/react-typescript-demo">this repository</a>.</p>
<p>If you want to master JavaScript, ES6+, React, and Node.js with easy-to-understand content, check out my <a target="_blank" href="https://www.youtube.com/@codingmastery_dev/">YouTube channel</a>. Don't forget to subscribe.</p>
<p>Want to stay up to date with regular content on JavaScript, React, and Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/">Follow me on LinkedIn</a>.</p>
<p><a target="_blank" href="https://courses.yogeshchavan.dev/build-expense-manager-app-using-react-and-typescript"><img src="https://www.freecodecamp.org/news/content/images/2023/11/expense_manager_app_banner.png" alt /></a></p>
]]></content:encoded></item><item><title><![CDATA[Build Expense Manager App Using React And TypeScript]]></title><description><![CDATA[Are you ready to supercharge your React with TypeScript skills and stay ahead in the competitive IT industry? ​
If yes, then check out my new course "Build Expense Manager App Using React and TypeScript," tailor-made to help you excel in the world of...]]></description><link>https://blog.yogeshchavan.dev/build-expense-manager-app-using-react-and-typescript</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/build-expense-manager-app-using-react-and-typescript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[React]]></category><category><![CDATA[#codenewbies]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Thu, 16 Nov 2023 06:46:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1700117119879/023b2dcb-0e76-4150-9f4d-9235cfaa0182.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Are you ready to supercharge your React with TypeScript skills and stay ahead in the competitive IT industry? ​</p>
<p>If yes, then check out my new course "<a target="_blank" href="https://courses.yogeshchavan.dev/build-expense-manager-app-using-react-and-typescript">Build Expense Manager App Using React and TypeScript</a>," tailor-made to help you excel in the world of modern web development.​</p>
<p><strong>Knowing TypeScript is an unavoidable part of the developer journey as almost all of the company/industry projects use TypeScript for building projects.</strong></p>
<p>So in this new course, you will learn how to build a complete Expense Manager App from scratch using React + TypeScript in a step-by-step way..</p>
<p>Want to know, what you will be building from scratch? check out <a target="_blank" href="https://courses.yogeshchavan.dev/view/courses/build-expense-manager-app-using-react-and-typescript/2268410-introduction/7204699-application-demo">this application demo</a>.</p>
<p>In today's tech-driven world, React and TypeScript have become essential tools for every developer.</p>
<p>If you are looking to enhance your expertise in these areas, this course is designed with you in mind.</p>
<p><strong>Whether you are a seasoned developer or just starting your journey, this course will provide you with the knowledge and skills you need to succeed.</strong></p>
<p>But don't just take my word for it – a lot of early participants who have been given access to the course to identify the quality of the course had this to say:</p>
<p><em>"This course is a no-brainer for anyone looking to stay ahead in this era of typescript and react industry. It's mind-blowing!".</em></p>
<p>Don't miss out on this opportunity to level up your skills and thrive in the ever-evolving tech industry. Join today and embark on a learning journey that will set you apart from the rest.</p>
<p><strong>I'm sure that, once you complete the course, you will have solid knowledge that will allow you to easily build any project using React and TypeScript.</strong></p>
<p>Last and the best part is that you also get access to the Discord community where you can get your doubts cleared. The link for the discord community is in the course.</p>
<p><em>After completing the course, you will also get the course certificate which you can access from your podia account.</em></p>
<p><strong>PS: I'm planning to extend this course with future updates which includes</strong></p>
<ul>
<li><p><strong>Updating course with Redux Toolkit Query(RTK) - Coming in next week</strong></p>
</li>
<li><p><strong>Testing Application using React Testing Library</strong></p>
</li>
<li><p><strong>Deploying the application to AWS</strong></p>
</li>
</ul>
<p>and much more...</p>
<p>So without thinking twice, click the below link to join the course at the course launch price of <strong>$13 instead of the regular price of $19.</strong></p>
<p><a target="_blank" href="https://courses.yogeshchavan.dev/build-expense-manager-app-using-react-and-typescript">JOIN THE REACT + TypeScript Course</a></p>
<p><strong>Grab the offer, before it goes away.</strong></p>
<h2 id="heading-thanks-for-reading"><strong>Thanks for Reading!</strong></h2>
<p>If you want to master JavaScript, ES6+, React and Node.js with easy-to-understand content, do check out my <a target="_blank" href="https://www.youtube.com/@codingmastery_dev/"><strong>YouTube channel</strong></a> and don't forget to subscribe.</p>
<p>Want to stay up to date with regular content regarding JavaScript, React, Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/"><strong>Follow me on LinkedIn</strong></a>.</p>
<p><a target="_blank" href="https://courses.yogeshchavan.dev/build-expense-manager-app-using-react-and-typescript"><img src="https://www.freecodecamp.org/news/content/images/2023/11/expense_manager_app_banner.png" alt="Build Expense Manager App Using React And TypeScript" /></a></p>
]]></content:encoded></item><item><title><![CDATA[How to Build an Image Search App With Pagination Using React]]></title><description><![CDATA[In this article, we will build step-by-step a beautiful Unsplash Image Search App with pagination using React.
By building this app, you will learn:

How to build an application using Unsplash API in React

How to make API Calls in different scenario...]]></description><link>https://blog.yogeshchavan.dev/how-to-build-an-image-search-app-with-pagination-using-react</link><guid isPermaLink="true">https://blog.yogeshchavan.dev/how-to-build-an-image-search-app-with-pagination-using-react</guid><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[#codenewbies]]></category><dc:creator><![CDATA[Yogesh Chavan]]></dc:creator><pubDate>Fri, 06 Oct 2023 05:19:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1696569222437/1b5597b3-535b-4412-86cc-ef94611e8a10.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, we will build step-by-step a beautiful Unsplash Image Search App with pagination using React.</p>
<p>By building this app, you will learn:</p>
<ul>
<li><p>How to build an application using Unsplash API in React</p>
</li>
<li><p>How to make API Calls in different scenarios</p>
</li>
<li><p>How to use <code>useCallback</code> hook to avoid function re-creation</p>
</li>
<li><p>How to use ESLint to fix application issues</p>
</li>
<li><p>How to Implement Pagination in React</p>
</li>
</ul>
<p>and much more...</p>
<p>Want to watch the video version of this tutorial? You can check out the video below:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=0YoT44j3Jg4&amp;list=PLSJnlFr3D-mFm7-cdhnHdBvUdxUp-a9HL">https://www.youtube.com/watch?v=0YoT44j3Jg4&amp;list=PLSJnlFr3D-mFm7-cdhnHdBvUdxUp-a9HL</a></div>
<p> </p>
<h2 id="heading-initial-project-setup"><strong>Initial Project Setup</strong></h2>
<p>We will use <a target="_blank" href="https://vitejs.dev/">Vite</a> to create a project which is a popular alternative to <code>create-react-app</code>.</p>
<p>Execute the following command to create a vite project:</p>
<pre><code class="lang-js">npm create vite
</code></pre>
<p>Once executed, you will be asked some questions.</p>
<p>For the project name, enter <code>unsplash_image_search</code>.</p>
<p>For framework, select <code>React</code> and for variant select <code>JavaScript</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/2_create_project.png" alt="Creating Project Using Vite" /></p>
<p>Once the project is created, open the project in VS Code and execute the following commands from the terminal:</p>
<pre><code class="lang-js">cd unsplash_image_search
npm install
npm run dev
</code></pre>
<p>Access the application by navigating to <a target="_blank" href="http://127.0.0.1:5173/">http://127.0.0.1:5173/</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/3_project_started.png" alt="Application Started" /></p>
<p>You will see the default application screen as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/1_app_screen.png" alt="Initial Screen" /></p>
<p>Next, delete the <code>App.css</code> file and replace the contents of the <code>App.jsx</code> file with the following content:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Welcome to Unsplash Image Search<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Now, open the <code>index.css</code> file and add the contents from <a target="_blank" href="https://github.com/myogeshchavan97/unsplash_image_search/blob/master/src/index.css">this GitHub repo</a> to it.</p>
<p>Let's install <a target="_blank" href="https://getbootstrap.com/">Bootstrap</a> and <a target="_blank" href="https://react-bootstrap.netlify.app/">react-bootstrap</a> npm packages by executing the following command:</p>
<pre><code class="lang-js">npm install bootstrap react-bootstrap
</code></pre>
<p>Open the <code>main.jsx</code> file and add the following line of code on the first line, to add the base bootstrap CSS file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">'bootstrap/dist/css/bootstrap.min.css'</span>;
</code></pre>
<p>The complete <code>main.jsx</code> file will look like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> <span class="hljs-string">'bootstrap/dist/css/bootstrap.min.css'</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.jsx'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

ReactDOM.createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)).render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">React.StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>
);
</code></pre>
<p>Now, restart the application by executing <code>npm run dev</code> command.</p>
<p>You will see the welcome message displayed on the screen as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/4_initial_screen.png" alt="Welcome Screen" /></p>
<h2 id="heading-how-to-add-search-input"><strong>How to Add Search Input</strong></h2>
<p>Now, replace the contents of <code>App.jsx</code> file with the following content:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Form } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-bootstrap'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'container'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'title'</span>&gt;</span>Image Search<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'search-section'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">'search'</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Type something to search...'</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">'search-input'</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here, we're displaying the title of <code>Image search</code> inside a <code>container</code> class, which is a Bootstrap class, to add some margin to the left and right of the page.</p>
<p>Then we added a <a target="_blank" href="https://react-bootstrap.netlify.app/docs/forms/overview/">form</a> with a type of <code>search</code>.</p>
<p>If you check the application, you will see the following screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/5_searchbox.png" alt="Initial Search UI" /></p>
<p>Now, we need to store the value entered by the user somewhere in the component.</p>
<p>As we will have only one input field on the page, we will use the <a target="_blank" href="https://react.dev/reference/react/useRef">useRef</a> hook instead of the <code>useState</code> hook.</p>
<p>Using the <code>useRef</code> hook does not re-render the component when its value changes, which is good for performance improvement. On the other hand, changing state re-renders the component, so all of the child components will also re-render.</p>
<p>Inside the <code>App.jsx</code> file, declare the <code>useRef</code> hook as shown below:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> searchInput = useRef(<span class="hljs-literal">null</span>);
</code></pre>
<p>Don't forget to add import for <code>useRef</code> hook at the top of the file:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
</code></pre>
<p>Also, add a <code>ref</code> prop for the search input, like this:</p>
<pre><code class="lang-jsx">&lt;Form.Control
   type=<span class="hljs-string">'search'</span>
   placeholder=<span class="hljs-string">'Type something to search...'</span>
   className=<span class="hljs-string">'search-input'</span>
   ref={searchInput}
/&gt;
</code></pre>
<p>Your complete <code>App.jsx</code> file will look like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Form } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-bootstrap'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> searchInput = useRef(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'container'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'title'</span>&gt;</span>Image Search<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'search-section'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">'search'</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Type something to search...'</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">'search-input'</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{searchInput}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h2 id="heading-how-to-handle-the-form-submit-action"><strong>How to Handle the Form Submit Action</strong></h2>
<p>When we enter any search term in the search box and press the enter key, we want to add the search functionality.</p>
<p>To do so, add an <code>onSubmit</code> handler to the <code>Form</code> tag and create a <code>handleSearch</code> method. And assign it to the <code>onSubmit</code> prop like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Form } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-bootstrap'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> searchInput = useRef(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'submitted'</span>);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'container'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'title'</span>&gt;</span>Image Search<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'search-section'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSearch}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">'search'</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Type something to search...'</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">'search-input'</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{searchInput}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>Here, we have added <code>&lt;Form onSubmit={handleSearch}&gt;</code> and inside the <code>handleSearch</code> method we used the <code>event.preventDefault</code> method.</p>
<p>Once the form is submitted by pressing the enter key in the search box, the page will not refresh and a submitted text will be displayed in the console as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/6_submitted.gif" alt="Form Submission Action" /></p>
<p>Now, instead of printing "submitted", we can print the value entered by the user using <code>searchInput.current.value</code>.</p>
<p>Here, <code>searchInput</code> is the <code>ref</code> and <code>searchInput.current</code> will be the actual search box input. Also, using <code>searchInput.current.value</code> will give the actual value entered by the user.</p>
<p>So, replace the <code>handleSearch</code> method with the following code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.preventDefault();
  <span class="hljs-built_in">console</span>.log(searchInput.current.value);
};
</code></pre>
<p>And now you will see the entered value displayed in the console:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/7_searchterm.gif" alt="Displaying Entered Search Term Value In Console" /></p>
<h2 id="heading-how-to-add-quick-search-options"><strong>How to Add Quick Search Options</strong></h2>
<p>Now, let's add action buttons with a class of <code>filters</code> for a quick search just below the <code>search-section</code> div:</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">'container'</span>&gt;
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'title'</span>&gt;</span>Image Search<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'search-section'</span>&gt;</span>
        ...
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'filters'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Nature<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Birds<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Cats<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Shoes<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/div&gt;
</code></pre>
<p>Now, the application will look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/8_buttons_added.png" alt="Quick Search Options Added" /></p>
<p>When we click on any of the displayed buttons, we can display the clicked button value in the input search box, so we can use it for searching the images.</p>
<p>Change the <code>filters</code> div to the below code:</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">'filters'</span>&gt;
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('nature')}&gt;Nature<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('birds')}&gt;Birds<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('cats')}&gt;Cats<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
   <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('shoes')}&gt;Shoes<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/div&gt;
</code></pre>
<p>In the above code, when you click on any option, we're passing the selected option to the <code>handleSelection</code> method.</p>
<p>Now, add a new <code>handleSelection</code> method inside the <code>App</code> component as shown below:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> handleSelection = <span class="hljs-function">(<span class="hljs-params">selection</span>) =&gt;</span> {
  searchInput.current.value = selection;
};
</code></pre>
<p>Your complete <code>App.jsx</code> file will look like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Form } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-bootstrap'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> searchInput = useRef(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
    <span class="hljs-built_in">console</span>.log(searchInput.current.value);
  };

  <span class="hljs-keyword">const</span> handleSelection = <span class="hljs-function">(<span class="hljs-params">selection</span>) =&gt;</span> {
    searchInput.current.value = selection;
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'container'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'title'</span>&gt;</span>Image Search<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'search-section'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSearch}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">'search'</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Type something to search...'</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">'search-input'</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{searchInput}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'filters'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('nature')}&gt;Nature<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('birds')}&gt;Birds<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('cats')}&gt;Cats<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('shoes')}&gt;Shoes<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/9_selection.gif" alt="Displaying Selection Option In the Search Box" /></p>
<h2 id="heading-how-to-get-access-to-the-unsplash-api"><strong>How to Get Access to the Unsplash API</strong></h2>
<p>Now, to implement the image search, we need to get the API key from <a target="_blank" href="https://unsplash.com/">Unsplash Website</a>.</p>
<p>Navigate to <a target="_blank" href="https://unsplash.com/developers">this URL</a>, and click on the "Register as a developer" button displayed at the top right corner of the page. Create your account by entering all the necessary details.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/10_register_as_developer.png" alt="10_register_as_developer" /></p>
<p>Once registered, you will be redirected to <a target="_blank" href="https://unsplash.com/oauth/applications">this page</a> as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/11_applications_page.png" alt="Registering New Application With Unsplash API" /></p>
<p>Click on the <code>New Application</code> button. On the next screen:</p>
<ul>
<li><p>Check all the checkboxes and click on <code>Accept Terms</code> button</p>
</li>
<li><p>Enter values for <code>Application name</code> and <code>Description</code> and click <code>Create application</code> button</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/13_create_application.gif" alt="Creating New Application With Unsplash API" /></p>
<p>Scroll down a bit and copy the <code>Access Key</code> which is displayed on the screen:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/14_access_key_copy.gif" alt="Getting Access Key From Unsplash API" /></p>
<p>Next, create a new <code>.env</code> file in your project and add a new environment variable with the name <code>VITE_API_KEY</code>. Also, assign the copied value of the API key to it:</p>
<pre><code class="lang-jsx">VITE_API_KEY=A4UiJ5OIwL_4ccbCAE1ZXw3EgoNRotMbdNe12qtKHzM
</code></pre>
<p>Make sure to start the variable name with <code>VITE_</code> so it will be accessible in the application.</p>
<p>Your application folder structure will look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/15_api_key.png" alt="File Structure With .env File" /></p>
<p>Also, make sure to add <code>.env</code> in the <code>.gitignore</code> file so the file will not be pushed to GitHub when changes are pushed to GitHub.</p>
<p>Now, navigate to <a target="_blank" href="https://unsplash.com/documentation">Unsplash Documentation</a> and click on the <code>Search photos by keyword</code> section. And copy the following base API URL: <a target="_blank" href="https://api.unsplash.com/search/photos"><code>https://api.unsplash.com/search/photos</code></a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/16_base_api_url.gif" alt="Search Images API Documentation Page" /></p>
<p>Now, open <code>App.jsx</code> file and paste that copied URL as <code>API_URL</code> after all import statements, like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> API_URL = <span class="hljs-string">'https://api.unsplash.com/search/photos'</span>;
</code></pre>
<p>According to the documentation, the search photos API with the above URL accepts the <code>query</code>, <code>page</code> and <code>per_page</code> as the query parameters. Just note this, as we will be using it soon.</p>
<h2 id="heading-how-to-make-an-api-call-to-the-unsplash-api"><strong>How to Make an API Call to the Unsplash API</strong></h2>
<p>To make an API call, let's first install the <code>axios</code> npm library by executing the following command from the project folder:</p>
<pre><code class="lang-js">npm install axios
</code></pre>
<p>Once installed, start the application again by executing the <code>npm run dev</code> command.</p>
<p>Next, declare a new constant just below the <code>API_URL</code> constant:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> IMAGES_PER_PAGE = <span class="hljs-number">20</span>;
</code></pre>
<p>Here, we're specifying to display <code>20</code> images per page when we will implement pagination. You can change it to any value you want.</p>
<p>Add a new <code>fetchImages</code> function inside the <code>App</code> component like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> fetchImages = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
      <span class="hljs-string">`<span class="hljs-subst">${API_URL}</span>?query=<span class="hljs-subst">${
        searchInput.current.value
      }</span>&amp;page=1&amp;per_page=<span class="hljs-subst">${IMAGES_PER_PAGE}</span>&amp;client_id=<span class="hljs-subst">${
        <span class="hljs-keyword">import</span>.meta.env.VITE_API_KEY
      }</span>`</span>
    );
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'data'</span>, data);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
  }
};
</code></pre>
<p>Here, we have defined a <code>fetchImages</code> function which is declared <code>async</code> so we can use <code>await</code> inside it.</p>
<blockquote>
<p>If you're not aware of promises and async/await, I highly recommend checking out <a target="_blank" href="https://www.freecodecamp.org/news/javascript-promises-async-await-and-promise-methods/">this article</a>.</p>
</blockquote>
<p>Then, inside the <code>fetchImages</code> function, we're making a GET API call using axios to the URL which we have stored in the <code>API_URL</code> constant: <a target="_blank" href="https://api.unsplash.com/search/photos"><code>https://api.unsplash.com/search/photos</code></a>.</p>
<p>For the API URL, we're passing the following query parameters using <a target="_blank" href="https://bit.ly/3rtiQ9y">template literal syntax</a>:</p>
<ul>
<li><p><code>query</code> with the value of user entered or quick search option value</p>
</li>
<li><p><code>page</code> with a value of <code>1</code> to get the first page data</p>
</li>
<li><p><code>per_page</code> with the value of <code>20</code> which is defined in the constant <code>IMAGES_PER_PAGE</code></p>
</li>
<li><p><code>client_id</code> with the value of the API key from the <code>.env</code> file.</p>
</li>
</ul>
<p>As we're using <a target="_blank" href="https://vitejs.dev/">Vite</a>, to access environment variables from the <code>.env</code> file, we need to use <code>import.meta.env.VITE_API_KEY</code>.</p>
<p>Here, <code>VITE_API_KEY</code> is the environment variable we declared in the <code>.env</code> file.</p>
<p>Also, import the <code>axios</code> library at the top of the file like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> axios;
</code></pre>
<p>The updated <code>App.jsx</code> file will look like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> React, { useRef } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Form } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-bootstrap'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

<span class="hljs-keyword">const</span> API_URL = <span class="hljs-string">'https://api.unsplash.com/search/photos'</span>;
<span class="hljs-keyword">const</span> IMAGES_PER_PAGE = <span class="hljs-number">20</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> searchInput = useRef(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> fetchImages = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
        <span class="hljs-string">`<span class="hljs-subst">${API_URL}</span>?query=<span class="hljs-subst">${
          searchInput.current.value
        }</span>&amp;page=1&amp;per_page=<span class="hljs-subst">${IMAGES_PER_PAGE}</span>&amp;client_id=<span class="hljs-subst">${
          <span class="hljs-keyword">import</span>.meta.env.VITE_API_KEY
        }</span>`</span>
      );
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'data'</span>, data);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
    }
  };

  <span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
    <span class="hljs-built_in">console</span>.log(searchInput.current.value);
  };

  <span class="hljs-keyword">const</span> handleSelection = <span class="hljs-function">(<span class="hljs-params">selection</span>) =&gt;</span> {
    searchInput.current.value = selection;
    fetchImages();
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'container'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'title'</span>&gt;</span>Image Search<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'search-section'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSearch}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">'search'</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Type something to search...'</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">'search-input'</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{searchInput}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'filters'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('nature')}&gt;Nature<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('birds')}&gt;Birds<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('cats')}&gt;Cats<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('shoes')}&gt;Shoes<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>If you check the application, you will see that, on every click of the quick search option, the API call is made to the Unsplash API, and we get the data for the selected option.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/17_api_result.gif" alt="Making API Call When Clicked Quick Search Option" /></p>
<p>To make an API call when we enter the search text and press enter key, we need to call the <code>fetchImages</code> function from the <code>handleSearch</code> function also.</p>
<p>To do this, add a call to <code>fetchImages</code> function inside the <code>handleSearch</code> function as shown below:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
    <span class="hljs-built_in">console</span>.log(searchInput.current.value);
    fetchImages();
};
</code></pre>
<p>Now, you will be able to see the API call made in the network tab when we enter a search text and press enter key.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/18_search_result.gif" alt="Making API Call When Entered Text In The Searchbox" /></p>
<h2 id="heading-how-to-store-api-data-using-state"><strong>How to Store API Data Using State</strong></h2>
<p>Now, let's display the images coming from the API on the screen.</p>
<p>To display them on the screen, we first need to store the data coming from the API.</p>
<p>If you see the structure of the API response, you will see as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/19_response.png" alt="API Response" /></p>
<p>So, declare two states in the <code>App.jsx</code> file: one for storing response images that are coming in the <code>results</code> property, and another for storing <code>total_pages</code> so we can implement the pagination.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> searchInput = useRef(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [images, setImages] = useState([]);
  <span class="hljs-keyword">const</span> [totalPages, setTotalPages] = useState(<span class="hljs-number">0</span>);
  ....
}
</code></pre>
<p>And update the <code>fetchImages</code> function to store the <code>data.results</code> using <code>setImages</code> and total pages using <code>setTotalPages</code> function:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> fetchImages = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
        <span class="hljs-string">`<span class="hljs-subst">${API_URL}</span>?query=<span class="hljs-subst">${
          searchInput.current.value
        }</span>&amp;page=1&amp;per_page=<span class="hljs-subst">${IMAGES_PER_PAGE}</span>&amp;client_id=<span class="hljs-subst">${
          <span class="hljs-keyword">import</span>.meta.env.VITE_API_KEY
        }</span>`</span>
      );
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'data'</span>, data);
      setImages(data.results);
      setTotalPages(data.total_pages);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
    }
  };
</code></pre>
<h2 id="heading-how-to-display-images-on-screen"><strong>How to Display Images On Screen</strong></h2>
<p>Now, let's display the images that we have stored in the <code>images</code> state variable.</p>
<p>If you expand the individual image response of the API, you can see the <code>id</code>, <code>alt_description</code>, <code>urls</code> properties which we can use to display individual images.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/20_api_response.gif" alt="API Response Properties" /></p>
<p>So, just after the <code>filters</code> div, add another div for displaying images like this:</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">'filters'</span>&gt;
  ...
&lt;/div&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'images'</span>&gt;</span>
  {images.map((image) =&gt; {
    return (
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
        <span class="hljs-attr">key</span>=<span class="hljs-string">{image.id}</span>
        <span class="hljs-attr">src</span>=<span class="hljs-string">{image.urls.small}</span>
        <span class="hljs-attr">alt</span>=<span class="hljs-string">{image.alt_description}</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">'image'</span>
      /&gt;</span>
    );
  })}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p>Here, we're displaying the <code>small</code> version of the image from the <code>urls</code> property of the individual image.</p>
<p>We can simplify the above code further. Inside the array <code>map</code> method, instead of using a curly bracket with a <code>return</code> keyword, we can re-write it like this:</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">'filters'</span>&gt;
  ...
&lt;/div&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'images'</span>&gt;</span>
{images.map((image) =&gt; (
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
    <span class="hljs-attr">key</span>=<span class="hljs-string">{image.id}</span>
    <span class="hljs-attr">src</span>=<span class="hljs-string">{image.urls.small}</span>
    <span class="hljs-attr">alt</span>=<span class="hljs-string">{image.alt_description}</span>
    <span class="hljs-attr">className</span>=<span class="hljs-string">'image'</span>
  /&gt;</span>
))}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p>Here, we're implicitly returning the JSX from the array <code>map</code> method by adding a round bracket around the JSX.</p>
<p>Now, If you search for any text, you will see the images displayed correctly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/21_displayed_images.gif" alt="Displayed Images When Clicked On Quick Search Icon" /></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/22_displayed_images.gif" alt="Displayed Images When Clicked On Quick Search Icon" /></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/23_displayed_images.gif" alt="Displayed Images After Entering Search Term" /></p>
<h2 id="heading-how-to-implement-pagination"><strong>How to Implement Pagination</strong></h2>
<p>Now, we will add previous and next buttons to see different sets of images.</p>
<p>So, first declare a new state in the <code>App</code> component as shown below:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [page, setPage] = useState(<span class="hljs-number">1</span>);
</code></pre>
<p>Inside the <code>fetchImages</code> function, change <code>page=1</code> to <code>page=${page}</code> so when we change the value of the <code>page</code>, images for the selected <code>page</code> will be loaded.</p>
<p>Add a new div with a class of <code>buttons</code> just below the <code>images</code> div as shown below:</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">'images'</span>&gt;
  ...
&lt;/div&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'buttons'</span>&gt;</span>
  {page &gt; 1 &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>&gt;</span>Previous<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>}
  {page <span class="hljs-tag">&lt; <span class="hljs-attr">totalPages</span> &amp;&amp; &lt;<span class="hljs-attr">Button</span>&gt;</span>Next<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p>In the above code, we show the <code>Previous</code> button only if the value of <code>page</code> is greater than <code>1</code>, which means for the first page, we will not see the <code>Previous</code> button.</p>
<p>And If the current value of <code>page</code> is less than the <code>totalPages</code>, then only we show the <code>Next</code> button. This means that for the last page, we will not see the <code>Next</code> button.</p>
<p>If you remember, we have already set the value of <code>totalPages</code> inside the <code>fetchImages</code> function by calling the <code>setTotalPages</code> function, and we're using it above to hide the <code>Next</code> button.</p>
<p>Also, don't forget to add import for <code>Button</code> component from <code>react-bootstrap</code> inside the <code>App</code> component:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Button } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-bootstrap'</span>;
</code></pre>
<p>Now, when we click on the <code>Previous</code> button, we need to <code>decrement</code> the value of the <code>page</code> state variable. And when we click on <code>Next</code> button, we need to <code>increment</code> the value of the <code>page</code> state variable.</p>
<p>So, let's add an <code>onClick</code> handler for both of these buttons as shown below:</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">'buttons'</span>&gt;
  {page &gt; <span class="hljs-number">1</span> &amp;&amp; (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setPage(page - 1)}&gt;Previous<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span></span>
  )}
  {page &lt; totalPages &amp;&amp; (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setPage(page + 1)}&gt;Next<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span></span>
  )}
&lt;/div&gt;
</code></pre>
<p>Let's console log the value of the <code>page</code> state variable, so we can see the value getting updated.</p>
<p>After <code>handleSelection</code> method, add console.log like this:</p>
<pre><code class="lang-jsx"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">'page'</span>, page);
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/24_pagination.gif" alt="Displaying Current Page Value In Console" /></p>
<p>As you can see above, initially for the first page, we don't see a <code>Previous</code> button.</p>
<p>And when we click on the <code>Next</code> button, we see the <code>Previous</code> and <code>Next</code> buttons, and the <code>page</code> value is also incremented by <code>1</code> as you can see in the console.</p>
<p>So, on every <code>Next</code> button click, the <code>page</code> value is incremented by <code>1</code>.  And on every <code>Previous</code> button click, the <code>page</code> value is decremented by <code>1</code>.</p>
<p>And when we come back to the first page, the <code>Previous</code> button is hidden again which is as expected.</p>
<p>As you might have noticed above, the page value changes on click of <code>Previous</code> and <code>Next</code> buttons but a new set of images are not loaded when we click of those buttons.</p>
<p>This is because we're not making the API call again with an updated page value when the page value changes.</p>
<p>So let's do just that.</p>
<p>Add a <code>useEffect</code> hook in the <code>App</code> component like this:</p>
<pre><code class="lang-jsx">useEffect(<span class="hljs-function">() =&gt;</span> {
  fetchImages();
}, [page]);
</code></pre>
<p>Now, every time we click on <code>Previous</code> or <code>Next</code> button, the <code>page</code> value changes, so the above <code>useEffect</code> hook will be executed, where we're calling the <code>fetchImages</code> function to load the next set of images.</p>
<p>Now, If you check the application, you will see images loaded correctly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/25_loading_next_images.gif" alt="Loading Next Set Of Images Using Pagination" /></p>
<p>As you can see above, we're correctly loading images when clicked on <code>Previous</code> or <code>Next</code> button.</p>
<p>But there is a small issue.</p>
<p>If we're not on the first or last page, we see the <code>Previous</code> and <code>Next</code> buttons and when we try to search for another term or click on quick search options, we still see the <code>Previous</code> button.</p>
<p>Ideally, when we search for another term or click on another quick search option, we should start from the first page, so only the <code>Next</code> button should be visible. But right now both <code>Previous</code> and <code>Next</code> buttons are visible as you can see below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/26_previous_not_resetting.gif" alt="Issue With Previous Buttons Not Hiding On Search" /></p>
<p>To fix this issue, we need to reset the <code>page</code> state value once we search for another term or click on another quick search option.</p>
<p>So inside the <code>handleSearch</code> and <code>handleSelection</code> methods, call <code>setPage</code> function with a value of <code>1</code> like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.preventDefault();
  <span class="hljs-built_in">console</span>.log(searchInput.current.value);
  fetchImages();
  setPage(<span class="hljs-number">1</span>);
};

<span class="hljs-keyword">const</span> handleSelection = <span class="hljs-function">(<span class="hljs-params">selection</span>) =&gt;</span> {
  searchInput.current.value = selection;
  fetchImages();
  setPage(<span class="hljs-number">1</span>);
};
</code></pre>
<p>As you can see, we're repeating the <code>fetchImages</code> and <code>setPage</code> function calls in both of these methods.</p>
<p>So, let's create another function with a name <code>resetSearch</code> and move the <code>fetchImages</code> and <code>setPage</code> function calls inside it. Let's call that function from <code>handleSearch</code> and <code>handleSelection</code> methods as shown below:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> resetSearch = <span class="hljs-function">() =&gt;</span> {
  setPage(<span class="hljs-number">1</span>);
  fetchImages();
};

<span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.preventDefault();
  <span class="hljs-built_in">console</span>.log(searchInput.current.value);
  resetSearch();
};

<span class="hljs-keyword">const</span> handleSelection = <span class="hljs-function">(<span class="hljs-params">selection</span>) =&gt;</span> {
  searchInput.current.value = selection;
  resetSearch();
};
</code></pre>
<p>Now, If you check the application, you will see that we always get the correct first page result displayed when clicking on the quick search option or entering any search term which is as expected.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/27_correctly_loading_first_page.gif" alt="Demo Of Previous Button Hidden On Every Search" /></p>
<p>Your entire <code>App.jsx</code> file will look like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>;
<span class="hljs-keyword">import</span> { useEffect, useRef, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { Button, Form } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-bootstrap'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;

<span class="hljs-keyword">const</span> API_URL = <span class="hljs-string">'https://api.unsplash.com/search/photos'</span>;
<span class="hljs-keyword">const</span> IMAGES_PER_PAGE = <span class="hljs-number">20</span>;

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> searchInput = useRef(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [images, setImages] = useState([]);
  <span class="hljs-keyword">const</span> [page, setPage] = useState(<span class="hljs-number">1</span>);
  <span class="hljs-keyword">const</span> [totalPages, setTotalPages] = useState(<span class="hljs-number">0</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetchImages();
  }, [page]);

  <span class="hljs-keyword">const</span> fetchImages = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
        <span class="hljs-string">`<span class="hljs-subst">${API_URL}</span>?query=<span class="hljs-subst">${
          searchInput.current.value
        }</span>&amp;page=<span class="hljs-subst">${page}</span>&amp;per_page=<span class="hljs-subst">${IMAGES_PER_PAGE}</span>&amp;client_id=<span class="hljs-subst">${
          <span class="hljs-keyword">import</span>.meta.env.VITE_API_KEY
        }</span>`</span>
      );
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'data'</span>, data);
      setImages(data.results);
      setTotalPages(data.total_pages);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
    }
  };

  <span class="hljs-keyword">const</span> resetSearch = <span class="hljs-function">() =&gt;</span> {
    setPage(<span class="hljs-number">1</span>);
    fetchImages();
  };

  <span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
    <span class="hljs-built_in">console</span>.log(searchInput.current.value);
    resetSearch();
  };

  <span class="hljs-keyword">const</span> handleSelection = <span class="hljs-function">(<span class="hljs-params">selection</span>) =&gt;</span> {
    searchInput.current.value = selection;
    resetSearch();
  };

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'page'</span>, page);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'container'</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'title'</span>&gt;</span>Image Search<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'search-section'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSearch}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Form.Control</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">'search'</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">'Type something to search...'</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">'search-input'</span>
            <span class="hljs-attr">ref</span>=<span class="hljs-string">{searchInput}</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">Form</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'filters'</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('nature')}&gt;Nature<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('birds')}&gt;Birds<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('cats')}&gt;Cats<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSelection('shoes')}&gt;Shoes<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'images'</span>&gt;</span>
        {images.map((image) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{image.id}</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">{image.urls.small}</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">{image.alt_description}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">'image'</span>
          /&gt;</span>
        ))}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'buttons'</span>&gt;</span>
        {page &gt; 1 &amp;&amp; (
          <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setPage(page - 1)}&gt;Previous<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
        )}
        {page <span class="hljs-tag">&lt; <span class="hljs-attr">totalPages</span> &amp;&amp; (
          &lt;<span class="hljs-attr">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setPage(page + 1)}&gt;Next<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
        )}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<h2 id="heading-how-to-find-bugs-using-eslint"><strong>How to Find Bugs Using ESLint</strong></h2>
<p>When working on a React application, you should always have the ESLint VS Code extension enabled.</p>
<p>This will make sure that your code is correct and it will not produce any unexpected results in the future.</p>
<p>Based on the ESLint configuration defined in the <code>.eslientrc</code> file, you will get helpful suggestions to improve your code.</p>
<p>So, open your VS Code Extensions panel and install the <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint">ESLint extension</a> as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/28_eslint_extension.png" alt="VS Code ESLint Extension" /></p>
<p>After installing the extension, if you check the <code>App.jsx</code> file, you will immediately see a yellow squiggly line for the <code>page</code> dependency of the <code>useEffect</code> hook. If you mouse hover over it, you will see the warning as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/29_missing_dependency.png" alt="ESLint Warning For useEffect Hook" /></p>
<p>As the warning indicates, we need to add a <code>fetchImages</code> dependency in the dependency array.</p>
<p>We're getting a warning because, in the functional component, on every re-render of the component, all the declared functions are re-created so their reference changes.</p>
<p>So, if we're using any outside variable or function inside the <code>useEffect</code> hook, we need to mention that in the dependencies, so whenever the dependency changes, the <code>useEffect</code> will be executed again.</p>
<p>To fix this, you can click on the quick fix link and select the "update the dependencies" option as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/30_updating_dependency.gif" alt="Updating useEffect Hook Dependency" /></p>
<p>All the missing dependencies will be automatically added to the dependency array.</p>
<p>You can also choose to manually add the dependency if you want.</p>
<p>However, with this change, you will see a new yellow warning for the <code>fetchImages</code> function as shown below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/31_fetchimages_warning.png" alt="ESLint Warning For useCallback" /></p>
<p>As I said previously, on every re-render of the component, the <code>fetchImages</code> function will be re-created and when it's changed, we again call the <code>fetchImages</code> function as it's added in the dependency.</p>
<p>To avoid that, we need to wrap the <code>fetchImages</code> function inside the <a target="_blank" href="https://react.dev/reference/react/useCallback">useCallback</a> hook as shown below:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> fetchImages = useCallback(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
      <span class="hljs-string">`<span class="hljs-subst">${API_URL}</span>?query=<span class="hljs-subst">${
        searchInput.current.value
      }</span>&amp;page=<span class="hljs-subst">${page}</span>&amp;per_page=<span class="hljs-subst">${IMAGES_PER_PAGE}</span>&amp;client_id=<span class="hljs-subst">${
        <span class="hljs-keyword">import</span>.meta.env.VITE_API_KEY
      }</span>`</span>
    );
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'data'</span>, data);
    setImages(data.results);
    setTotalPages(data.total_pages);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
  }
}, [page]);
</code></pre>
<p>In the above code, we're passing <code>page</code> as a dependency because, <code>page</code> is an external variable whose value might change in the future when we click on <code>Previous</code> or <code>Next</code> buttons or search for any new term.</p>
<p>If changing variables are used inside <code>useEffect</code> or <code>useCallback</code> or <code>useMemo</code> hook, we need to add them in the dependencies list.</p>
<p>Now, you will not see any more warnings in the <code>App</code> component.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/32_no_warnings.gif" alt="Fixed ESLint Warning of useCallback" /></p>
<p>However, If you check the browser console, you will see an error and nothing is displayed on the UI as the application has crashed.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/33_access_before_initialization.png" alt="Function Expression Related Console Error" /></p>
<p>We're getting errors because we have declared <code>fetchImages</code> function using the function expression syntax, and functions declared using function expression syntax cannot be called before defining them.</p>
<p>Assigning a function to a variable makes it a function expression.</p>
<p>As you can see in the below image, we're calling <code>fetchImages</code> function on line number 16 and we're declaring the function on line number 19 and functions declared using function expression syntax cannot be accessed before the declaration.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/34_function_expression_error.png" alt="Cause of Console Error" /></p>
<p>To fix this, we need to declare the function before calling it. So, move the <code>fetchImages</code> function before the useEffect hook and it will fix the issue.</p>
<p>Your <code>App</code> component will look like this:</p>
<pre><code class="lang-jsx">
<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> searchInput = useRef(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [images, setImages] = useState([]);
  <span class="hljs-keyword">const</span> [page, setPage] = useState(<span class="hljs-number">1</span>);
  <span class="hljs-keyword">const</span> [totalPages, setTotalPages] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">const</span> fetchImages = useCallback(<span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
        <span class="hljs-string">`<span class="hljs-subst">${API_URL}</span>?query=<span class="hljs-subst">${
          searchInput.current.value
        }</span>&amp;page=<span class="hljs-subst">${page}</span>&amp;per_page=<span class="hljs-subst">${IMAGES_PER_PAGE}</span>&amp;client_id=<span class="hljs-subst">${
          <span class="hljs-keyword">import</span>.meta.env.VITE_API_KEY
        }</span>`</span>
      );
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'data'</span>, data);
      setImages(data.results);
      setTotalPages(data.total_pages);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.log(error);
    }
  }, [page]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    fetchImages();
  }, [fetchImages, page]);

  <span class="hljs-keyword">const</span> resetSearch = <span class="hljs-function">() =&gt;</span> {
    setPage(<span class="hljs-number">1</span>);
    fetchImages();
  };
  ...
}
</code></pre>
<p>Now, If you check the application, there will not be any error and the application will work as expected.</p>
<h2 id="heading-code-improvements"><strong>Code Improvements</strong></h2>
<p>Right now, we have not added any validation in the current application when the user enters a search term.</p>
<p>When the page is loaded, and when we don't enter any text and directly press the enter key in the input search box, we're making an API call which is not good.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/35_extra_api_call.gif" alt="Demo Of API Calls Made Without Any Value" /></p>
<p>To fix this, before making the API call, we first need to check if the <code>searchInput.current.value</code> is not empty and then only make the API call.</p>
<p>Change the <code>fetchImages</code> function from this code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> fetchImages = useCallback(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
      <span class="hljs-string">`<span class="hljs-subst">${API_URL}</span>?query=<span class="hljs-subst">${
        searchInput.current.value
      }</span>&amp;page=<span class="hljs-subst">${page}</span>&amp;per_page=<span class="hljs-subst">${IMAGES_PER_PAGE}</span>&amp;client_id=<span class="hljs-subst">${
        <span class="hljs-keyword">import</span>.meta.env.VITE_API_KEY
      }</span>`</span>
    );
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'data'</span>, data);
    setImages(data.results);
    setTotalPages(data.total_pages);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
  }
}, [page]);
</code></pre>
<p>to the below code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> fetchImages = useCallback(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">if</span> (searchInput.current.value) {
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
        <span class="hljs-string">`<span class="hljs-subst">${API_URL}</span>?query=<span class="hljs-subst">${
          searchInput.current.value
        }</span>&amp;page=<span class="hljs-subst">${page}</span>&amp;per_page=<span class="hljs-subst">${IMAGES_PER_PAGE}</span>&amp;client_id=<span class="hljs-subst">${
          <span class="hljs-keyword">import</span>.meta.env.VITE_API_KEY
        }</span>`</span>
      );
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'data'</span>, data);
      setImages(data.results);
      setTotalPages(data.total_pages);
    }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.log(error);
  }
}, [page]);
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/36_no_api_calls.gif" alt="Fixed Issue of API Calls Without Any Value" /></p>
<p>As you can see above, initially on page load and without entering any value, if we press the enter key, no API call is made.</p>
<p>Only when we type something and press enter, the API call is made, which is a good improvement to the application.</p>
<h2 id="heading-how-to-remove-an-extra-dependency-from-useeffect"><strong>How to Remove an Extra Dependency From</strong> <code>useEffect</code></h2>
<p>As we have added a <code>useCallback</code> hook for the <code>fetchImages</code> function which has a <code>page</code> dependency, we no longer need the extra <code>page</code> dependency for the <code>useEffect</code> hook.</p>
<p>So change the below code:</p>
<pre><code class="lang-jsx">useEffect(<span class="hljs-function">() =&gt;</span> {
  fetchImages();
}, [fetchImages, page]);
</code></pre>
<p>to this code:</p>
<pre><code class="lang-jsx">useEffect(<span class="hljs-function">() =&gt;</span> {
  fetchImages();
}, [fetchImages]);
</code></pre>
<p>and the application will work as before without any issues.</p>
<h2 id="heading-how-to-display-loading-indication"><strong>How to Display Loading Indication</strong></h2>
<p>As you might have noticed in the previous image, when we searched for the text <code>hello</code>, the results were not displayed immediately.</p>
<p>As we're making an API call when searching for something, depending on the network speed, it might take some time to get the data from the API.</p>
<p>So while the API call is still going on, we can display a loading message, and once we get the response from the API, we will display the images.</p>
<p>To achieve that, declare a new loading state in the <code>App</code> component with an initial value of <code>false</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [loading, setLoading] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<p>And now change the <code>fetchImages</code> function to the below code:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> fetchImages = useCallback(<span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">if</span> (searchInput.current.value) {
      setErrorMsg(<span class="hljs-string">''</span>);
      setLoading(<span class="hljs-literal">true</span>);
      <span class="hljs-keyword">const</span> { data } = <span class="hljs-keyword">await</span> axios.get(
        <span class="hljs-string">`<span class="hljs-subst">${API_URL}</span>?query=<span class="hljs-subst">${
          searchInput.current.value
        }</span>&amp;page=<span class="hljs-subst">${page}</span>&amp;per_page=<span class="hljs-subst">${IMAGES_PER_PAGE}</span>&amp;client_id=<span class="hljs-subst">${
          <span class="hljs-keyword">import</span>.meta.env.VITE_API_KEY
        }</span>`</span>
      );
      setImages(data.results);
      setTotalPages(data.total_pages);
      setLoading(<span class="hljs-literal">false</span>);
    }
  } <span class="hljs-keyword">catch</span> (error) {
    setErrorMsg(<span class="hljs-string">'Error fetching images. Try again later.'</span>);
    <span class="hljs-built_in">console</span>.log(error);
    setLoading(<span class="hljs-literal">false</span>);
  }
}, [page]);
</code></pre>
<p>As you can see above, we're calling <code>setLoading(true)</code> before the API call and <code>setLoading(false)</code> after the API call.</p>
<p>Note that, we're also calling <code>`setLoading(false)</code>inside the catch block.</p>
<p>So, even if the API is successful or failed, we're setting <code>loading</code> state to <code>false</code> so we will not see the loading message all the time.</p>
<p>Now, to display the loading message change the below code:</p>
<pre><code class="lang-jsx">&lt;div className=<span class="hljs-string">'images'</span>&gt;
  {images.map(<span class="hljs-function">(<span class="hljs-params">image</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
      <span class="hljs-attr">key</span>=<span class="hljs-string">{image.id}</span>
      <span class="hljs-attr">src</span>=<span class="hljs-string">{image.urls.small}</span>
      <span class="hljs-attr">alt</span>=<span class="hljs-string">{image.alt_description}</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">'image'</span>
    /&gt;</span></span>
  ))}
&lt;/div&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'buttons'</span>&gt;</span>
  {page &gt; 1 &amp;&amp; (
    <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setPage(page - 1)}&gt;Previous<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
  )}
  {page <span class="hljs-tag">&lt; <span class="hljs-attr">totalPages</span> &amp;&amp; (
    &lt;<span class="hljs-attr">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setPage(page + 1)}&gt;Next<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
  )}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
</code></pre>
<p>to this code:</p>
<pre><code class="lang-jsx">{loading ? (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'loading'</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
) : (
  <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'images'</span>&gt;</span>
      {images.map((image) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
          <span class="hljs-attr">key</span>=<span class="hljs-string">{image.id}</span>
          <span class="hljs-attr">src</span>=<span class="hljs-string">{image.urls.small}</span>
          <span class="hljs-attr">alt</span>=<span class="hljs-string">{image.alt_description}</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">'image'</span>
        /&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">'buttons'</span>&gt;</span>
      {page &gt; 1 &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setPage(page - 1)}&gt;Previous<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
      )}
      {page <span class="hljs-tag">&lt; <span class="hljs-attr">totalPages</span> &amp;&amp; (
        &lt;<span class="hljs-attr">Button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setPage(page + 1)}&gt;Next<span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/&gt;</span></span>
)}
</code></pre>
<p>In the above code, if loading is true, then we're displaying a loading message. Otherwise, we're displaying the images coming from the API.</p>
<p>If you check the application, you will see that the loading indication is displaying correctly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/09/37_loading_indication.gif" alt="Loading Indication Demo" /></p>
<h2 id="heading-thanks-for-reading"><strong>Thanks for Reading</strong></h2>
<p>That's it for this tutorial. I hope you learned a lot from it.</p>
<p>You can find the complete source code for this application in <a target="_blank" href="https://github.com/myogeshchavan97/unsplash_image_search">this repository</a>.</p>
<p>Want to watch the video version of this tutorial? You can check out <a target="_blank" href="https://www.youtube.com/watch?v=0YoT44j3Jg4&amp;list=PLSJnlFr3D-mFm7-cdhnHdBvUdxUp-a9HL&amp;index=17">this video.</a></p>
<p>If you want to master JavaScript, ES6+, React, and Node.js with easy-to-understand content, check out my <a target="_blank" href="https://www.youtube.com/@codingmastery_dev/">YouTube channel</a>. Don't forget to subscribe.</p>
<p>Want to stay up to date with regular content on JavaScript, React, and Node.js? <a target="_blank" href="https://www.linkedin.com/in/yogesh-chavan97/">Follow me on LinkedIn</a>.</p>
]]></content:encoded></item></channel></rss>