<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ React - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ React - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 06 May 2026 11:21:50 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/react/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Full-Stack SaaS App with TanStack Start, Elysia, and Neon ]]>
                </title>
                <description>
                    <![CDATA[ Most full-stack React tutorials stop at "Hello World." They show you how to render a component, maybe fetch some data, and call it a day. But when you sit down to build a real SaaS application, you im ]]>
                </description>
                <link>https://www.freecodecamp.org/news/full-stack-saas-tanstack-start-elysia-neon/</link>
                <guid isPermaLink="false">69ce8f9b0ff860b6defe701d</guid>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Magnus Rødseth ]]>
                </dc:creator>
                <pubDate>Thu, 02 Apr 2026 15:47:39 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/ae3ac13a-e6b4-4498-aa32-ebd8c60c44a2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Most full-stack React tutorials stop at "Hello World." They show you how to render a component, maybe fetch some data, and call it a day.</p>
<p>But when you sit down to build a real SaaS application, you immediately hit a wall of unanswered questions. How do you structure your database? Where does authentication live? How do you make API calls type-safe? How do you handle payments without losing webhooks?</p>
<p>This handbook answers all of those questions. You'll build a production-ready SaaS application from scratch using TanStack Start, Elysia, Drizzle ORM, Neon PostgreSQL, Better Auth, Stripe, and Inngest.</p>
<p>By the end, you will have a deployed application with authentication, a type-safe API, database migrations, payment processing, and background jobs.</p>
<p>I chose this stack after building production applications with Next.js, Express, and Prisma. The combination of TanStack Start and Elysia with Eden Treaty gives you something rare: end-to-end type safety from your database schema to your React components, with zero code generation.</p>
<p>Change a column in your database, and TypeScript tells you everywhere that needs updating. That feedback loop changes how you build software.</p>
<p>Here's what you'll learn:</p>
<ul>
<li><p>How to set up a TanStack Start project with Vite and file-based routing</p>
</li>
<li><p>How to configure a PostgreSQL database with Drizzle ORM and Neon</p>
</li>
<li><p>How to build a type-safe API with Elysia embedded in your web app</p>
</li>
<li><p>How to connect your frontend to your API with Eden Treaty</p>
</li>
<li><p>How to add GitHub OAuth authentication with Better Auth</p>
</li>
<li><p>How to build complete features using a repeatable four-layer pattern</p>
</li>
<li><p>How to process payments with Stripe webhooks</p>
</li>
<li><p>How to run reliable background jobs with Inngest</p>
</li>
<li><p>How to deploy everything to Vercel with Neon</p>
</li>
</ul>
<h3 id="heading-why-tanstack-start-instead-of-nextjs">Why TanStack Start Instead of Next.js?</h3>
<p>You might be wondering –&nbsp;why not just use Next.js? It's the default choice for full-stack React, and for good reason. Next.js pioneered server-side rendering, established conventions that shaped the React ecosystem, and has the largest community of any React framework.</p>
<p>But TanStack Start has three advantages that matter for this kind of project.</p>
<h4 id="heading-1-deployment-flexibility">1. Deployment flexibility</h4>
<p>TanStack Start compiles to standard JavaScript that runs anywhere: Node.js, Bun, Deno, Cloudflare Workers, AWS Lambda, or your own server. Next.js is notoriously difficult to self-host outside of Vercel.</p>
<p>If you search "Next.js Azure App Service container" or "Next.js ISR self-hosted," you'll find years of Stack Overflow questions about edge cases that only appear in production.</p>
<h4 id="heading-2-simpler-mental-model">2. Simpler mental model</h4>
<p>Next.js has grown complex: the App Router, React Server Components, Server Actions, partial prerendering, <code>cache()</code>, <code>unstable_cache()</code>, plus various rendering strategies.</p>
<p>TanStack Start uses full-document SSR with full hydration. There's no opaque server/client boundary confusion. The tradeoff is that you don't get RSC's granular streaming, but you gain clarity and predictability.</p>
<h4 id="heading-3-end-to-end-type-safety">3. End-to-end type safety</h4>
<p>Combined with Elysia and Eden Treaty, TanStack Start gives you compile-time type inference from your database to your UI. No code generation steps. No schema files to keep in sync.</p>
<p>TanStack Router itself provides fully type-safe routing with inferred path params, search params, and loader data.</p>
<p>This is a handbook, so it goes deep. Set aside a few hours, open your editor, and let's build something real.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-how-to-set-up-the-project">How to Set Up the Project</a></p>
</li>
<li><p><a href="#heading-how-to-configure-the-database-with-drizzle-and-neon">How to Configure the Database with Drizzle and Neon</a></p>
</li>
<li><p><a href="#heading-how-to-build-the-api-with-elysia">How to Build the API with Elysia</a></p>
</li>
<li><p><a href="#heading-how-to-add-type-safe-api-calls-with-eden-treaty">How to Add Type-Safe API Calls with Eden Treaty</a></p>
</li>
<li><p><a href="#heading-how-to-add-authentication-with-better-auth">How to Add Authentication with Better Auth</a></p>
</li>
<li><p><a href="#heading-how-to-build-a-complete-feature-the-four-layer-pattern">How to Build a Complete Feature (The Four-Layer Pattern)</a></p>
</li>
<li><p><a href="#heading-how-to-add-payments-with-stripe">How to Add Payments with Stripe</a></p>
</li>
<li><p><a href="#heading-how-to-add-background-jobs-with-inngest">How to Add Background Jobs with Inngest</a></p>
</li>
<li><p><a href="#heading-how-to-deploy-to-vercel-with-neon">How to Deploy to Vercel with Neon</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before you start, make sure you have the following installed:</p>
<ul>
<li><p><a href="https://bun.sh"><strong>Bun</strong></a> (v1.2 or later) for package management and running scripts</p>
</li>
<li><p><a href="https://www.docker.com/products/docker-desktop/"><strong>Docker</strong></a> for running PostgreSQL locally</p>
</li>
<li><p><a href="https://git-scm.com/"><strong>Git</strong></a> for version control</p>
</li>
<li><p>Basic knowledge of React and TypeScript</p>
</li>
</ul>
<p>You'll also need free accounts on these services:</p>
<ul>
<li><p><a href="https://neon.tech"><strong>Neon</strong></a> for your production PostgreSQL database</p>
</li>
<li><p><a href="https://vercel.com"><strong>Vercel</strong></a> for deployment</p>
</li>
<li><p><a href="https://github.com"><strong>GitHub</strong></a> for OAuth authentication (you will create an OAuth app)</p>
</li>
<li><p><a href="https://stripe.com"><strong>Stripe</strong></a> for payment processing (test mode is free)</p>
</li>
</ul>
<p>All of these services have generous free tiers. You won't need to pay anything to follow this tutorial.</p>
<p>You should also be comfortable reading TypeScript code. This handbook assumes you understand generics, type inference, and async/await. If you're new to TypeScript, the <a href="https://www.typescriptlang.org/docs/handbook/">official handbook</a> is a solid starting point.</p>
<h2 id="heading-how-to-set-up-the-project">How to Set Up the Project</h2>
<p>Start by creating a new TanStack Start project. TanStack provides a CLI that scaffolds a project with file-based routing, Vite, and server-side rendering out of the box.</p>
<pre><code class="language-bash">bunx @tanstack/cli@latest create my-saas
cd my-saas
bun install
</code></pre>
<p>The CLI will ask you a few questions. Choose React as your framework and accept the defaults for the rest.</p>
<p>You're using Bun as your package manager and runtime. Bun is significantly faster than npm for installing dependencies and running scripts. It also natively supports TypeScript execution, which means you can run <code>.ts</code> files directly without a compilation step.</p>
<p>If you prefer npm or pnpm, the commands are similar, but this tutorial uses Bun throughout.</p>
<h3 id="heading-how-to-understand-the-project-structure">How to Understand the Project Structure</h3>
<p>Before writing any code, let's look at how you'll organize this project. The key architectural decision is putting all library code under <code>src/lib/</code>. Each integration (database, auth, payments, and so on) gets its own directory with a clean public API through an <code>index.ts</code> file.</p>
<p>Here's the structure you'll build toward:</p>
<pre><code class="language-text">my-saas/
├── src/
│   ├── components/          # React components
│   ├── hooks/               # Custom React hooks
│   ├── lib/
│   │   ├── auth/            # Better Auth (server + client)
│   │   ├── db/              # Drizzle ORM + schema
│   │   ├── jobs/            # Inngest background jobs
│   │   └── payments/        # Stripe integration
│   ├── routes/              # TanStack file-based routing
│   ├── server/
│   │   ├── api.ts           # Elysia API definition
│   │   └── routes/          # API route modules
│   └── start.ts             # TanStack Start entry point
├── docker-compose.yml       # Local PostgreSQL + Neon proxy
├── drizzle.config.ts        # Drizzle Kit configuration
├── vite.config.ts           # Vite + TanStack Start config
└── package.json
</code></pre>
<p>Here's how all the pieces connect:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69a694d8d4dc9b42434c218f/5bf61d3b-0587-445a-8be1-79f869aa554b.png" alt="Full-stack SaaS architecture diagram showing TanStack Start handling the frontend, connected to an embedded Elysia API server that integrates with Better Auth for authentication, Stripe for payments, and Inngest for background jobs, with Drizzle ORM providing type-safe database access to Neon PostgreSQL" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>TanStack Start handles your frontend. It talks to an Elysia API server embedded in the same project. Elysia connects to three external services: Better Auth for authentication, Stripe for payments, and Inngest for background jobs. Below the API layer, Drizzle ORM provides type-safe database access to Neon PostgreSQL.</p>
<p>You'll build each layer one at a time, starting with the database.</p>
<p>This pattern keeps every integration isolated. When you need to change how authentication works, you go to <code>src/lib/auth/</code>. When you need to modify the database schema, you go to <code>src/lib/db/</code>. Nothing leaks across boundaries.</p>
<h3 id="heading-how-to-configure-vite">How to Configure Vite</h3>
<p>TanStack Start runs on Vite. Your <code>vite.config.ts</code> needs the TanStack Start plugin, the React plugin, and path resolution for the <code>@/</code> import alias:</p>
<pre><code class="language-typescript">// vite.config.ts
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import viteReact from "@vitejs/plugin-react";
import { defineConfig } from "vite";
import tsConfigPaths from "vite-tsconfig-paths";

export default defineConfig({
  server: {
    port: 3000,
  },
  plugins: [
    tsConfigPaths({
      projects: ["./tsconfig.json"],
    }),
    tanstackStart(),
    viteReact(),
  ],
});
</code></pre>
<p>The <code>tsConfigPaths</code> plugin reads the <code>paths</code> setting from your <code>tsconfig.json</code>, so you can use <code>@/lib/db</code> instead of <code>../../lib/db</code> throughout your code.</p>
<p>Add this to your <code>tsconfig.json</code>:</p>
<pre><code class="language-json">{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
</code></pre>
<h3 id="heading-how-to-install-dependencies">How to Install Dependencies</h3>
<p>Install the core dependencies you'll need throughout this tutorial:</p>
<pre><code class="language-bash"># Framework and routing
bun add @tanstack/react-router @tanstack/react-start react react-dom

# API layer
bun add elysia @elysiajs/eden

# Database
bun add drizzle-orm @neondatabase/serverless ws
bun add -d drizzle-kit

# Authentication
bun add better-auth

# Payments
bun add stripe

# Background jobs
bun add inngest

# Build tools
bun add -d @vitejs/plugin-react vite vite-tsconfig-paths typescript
</code></pre>
<p>Now you have a working TanStack Start project with all the dependencies you'll need. Start the dev server to make sure everything works:</p>
<pre><code class="language-bash">bun run dev
</code></pre>
<p>Visit <code>http://localhost:3000</code> and you should see your app running.</p>
<h2 id="heading-how-to-configure-the-database-with-drizzle-and-neon">How to Configure the Database with Drizzle and Neon</h2>
<p>Every SaaS needs a database. You'll use Drizzle ORM with Neon PostgreSQL. Drizzle gives you type-safe database queries that look like SQL, and Neon gives you a serverless PostgreSQL database that scales to zero when you aren't using it.</p>
<h3 id="heading-why-drizzle-instead-of-prisma">Why Drizzle Instead of Prisma?</h3>
<p>If you have used an ORM in the TypeScript ecosystem before, it was probably Prisma. Prisma is excellent for many use cases, but it has a key limitation for this architecture: it uses code generation.</p>
<p>You write a <code>.prisma</code> schema file, run <code>prisma generate</code>, and Prisma generates a TypeScript client. That generation step adds friction to your development loop and creates artifacts you need to keep in sync.</p>
<p>Drizzle takes a different approach. Your schema is TypeScript. Your queries are TypeScript. Types are inferred at compile time without any generation step.</p>
<p>When you add a column to a table, the types update immediately. This fits perfectly with the rest of the stack, where types flow from Drizzle through Elysia to Eden Treaty without any intermediate steps.</p>
<p>Drizzle also produces SQL that looks like SQL. If you know PostgreSQL, you can read Drizzle queries. There is no Prisma-specific query language to learn.</p>
<h3 id="heading-how-to-set-up-local-postgresql-with-docker">How to Set Up Local PostgreSQL with Docker</h3>
<p>For local development, you'll run PostgreSQL in Docker with a Neon-compatible proxy. This lets you use the same Neon serverless driver locally that you'll use in production.</p>
<p>Create a <code>docker-compose.yml</code> at the project root:</p>
<pre><code class="language-yaml"># docker-compose.yml
services:
  postgres:
    image: postgres:17
    container_name: my-saas-postgres
    restart: unless-stopped
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: my_saas
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  neon-proxy:
    image: ghcr.io/timowilhelm/local-neon-http-proxy:main
    container_name: my-saas-neon-proxy
    restart: unless-stopped
    environment:
      - PG_CONNECTION_STRING=postgres://postgres:postgres@postgres:5432/my_saas
    ports:
      - "4444:4444"
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  postgres_data:
</code></pre>
<p>The <code>neon-proxy</code> container is the important part. It translates HTTP requests into PostgreSQL wire protocol, which means your Neon serverless driver works locally without any code changes.</p>
<p>In production, Neon handles this translation on their infrastructure. Locally, you need this proxy to bridge the gap between the HTTP-based Neon driver and your plain PostgreSQL container.</p>
<p>The <code>healthcheck</code> on the PostgreSQL container ensures the proxy only starts after the database is ready. Without this, the proxy would try to connect to a database that's still initializing, causing connection errors on first startup.</p>
<p>Start the containers:</p>
<pre><code class="language-bash">docker compose up -d
</code></pre>
<h3 id="heading-how-to-define-your-schema">How to Define Your Schema</h3>
<p>Create the database client and schema. Start with <code>src/lib/db/index.ts</code> for the connection:</p>
<pre><code class="language-typescript">// src/lib/db/index.ts
import { neon, neonConfig } from "@neondatabase/serverless";
import { drizzle } from "drizzle-orm/neon-http";
import ws from "ws";

import * as schema from "./schema";

const isProduction = process.env.NODE_ENV === "production";
const LOCAL_DB_HOST = "db.localtest.me";

let connectionString = process.env.DATABASE_URL;

if (!connectionString) {
  throw new Error("DATABASE_URL environment variable is not set");
}

neonConfig.webSocketConstructor = ws;

if (!isProduction) {
  connectionString = `postgres://postgres:postgres@${LOCAL_DB_HOST}:5432/my_saas`;
  neonConfig.fetchEndpoint = (host) =&gt; {
    const [protocol, port] =
      host === LOCAL_DB_HOST ? ["http", 4444] : ["https", 443];
    return `\({protocol}://\){host}:${port}/sql`;
  };
  neonConfig.useSecureWebSocket = false;
  neonConfig.wsProxy = (host) =&gt;
    host === LOCAL_DB_HOST ? `\({host}:4444/v2` : `\){host}/v2`;
}

const client = neon(connectionString);
export const db = drizzle({ client, schema });

export * from "./schema";
</code></pre>
<p>The <code>db.localtest.me</code> hostname resolves to <code>127.0.0.1</code> and is the standard way to work with the local Neon proxy. In production, the Neon driver connects directly to your Neon database using the <code>DATABASE_URL</code> environment variable.</p>
<p>Now define your schema in <code>src/lib/db/schema.ts</code>. For a SaaS application, you need users, sessions, accounts (for OAuth), and a table for your core business entity. Here's a real production schema:</p>
<pre><code class="language-typescript">// src/lib/db/schema.ts
import {
  boolean,
  integer,
  pgEnum,
  pgTable,
  text,
  timestamp,
  varchar,
} from "drizzle-orm/pg-core";

export const purchaseTierEnum = pgEnum("purchase_tier", ["pro"]);
export const purchaseStatusEnum = pgEnum("purchase_status", [
  "completed",
  "partially_refunded",
  "refunded",
]);

export const users = pgTable("users", {
  id: text("id").primaryKey(),
  email: varchar("email", { length: 255 }).notNull().unique(),
  emailVerified: boolean("email_verified").notNull().default(false),
  name: text("name"),
  image: text("image"),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

export const sessions = pgTable("sessions", {
  id: text("id").primaryKey(),
  userId: text("user_id")
    .notNull()
    .references(() =&gt; users.id, { onDelete: "cascade" }),
  token: text("token").notNull().unique(),
  expiresAt: timestamp("expires_at").notNull(),
  ipAddress: text("ip_address"),
  userAgent: text("user_agent"),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

export const accounts = pgTable("accounts", {
  id: text("id").primaryKey(),
  userId: text("user_id")
    .notNull()
    .references(() =&gt; users.id, { onDelete: "cascade" }),
  accountId: text("account_id").notNull(),
  providerId: text("provider_id").notNull(),
  accessToken: text("access_token"),
  refreshToken: text("refresh_token"),
  accessTokenExpiresAt: timestamp("access_token_expires_at"),
  refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
  scope: text("scope"),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

export const verifications = pgTable("verifications", {
  id: text("id").primaryKey(),
  identifier: text("identifier").notNull(),
  value: text("value").notNull(),
  expiresAt: timestamp("expires_at").notNull(),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

export const purchases = pgTable("purchases", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() =&gt; crypto.randomUUID()),
  userId: text("user_id")
    .notNull()
    .references(() =&gt; users.id, { onDelete: "cascade" }),
  stripeCheckoutSessionId: text("stripe_checkout_session_id")
    .notNull()
    .unique(),
  stripeCustomerId: text("stripe_customer_id"),
  stripePaymentIntentId: text("stripe_payment_intent_id"),
  tier: purchaseTierEnum("tier").notNull(),
  status: purchaseStatusEnum("status").notNull().default("completed"),
  amount: integer("amount").notNull(),
  currency: text("currency").notNull().default("usd"),
  purchasedAt: timestamp("purchased_at").notNull().defaultNow(),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

// Type exports for use in your application
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;
export type Purchase = typeof purchases.$inferSelect;
export type NewPurchase = typeof purchases.$inferInsert;
</code></pre>
<p>Push the schema to create the tables:</p>
<pre><code class="language-bash">bun run db:push
</code></pre>
<p>A few things to notice about this schema:</p>
<ol>
<li><p>The <code>users</code>, <code>sessions</code>, <code>accounts</code>, and <code>verifications</code> tables are required by Better Auth. You'll configure the auth library to use these tables in the next section.</p>
</li>
<li><p>The <code>purchases</code> table is your core business entity. It tracks Stripe checkout sessions and links them to users.</p>
</li>
<li><p>Type exports like <code>User</code> and <code>Purchase</code> give you inferred TypeScript types from your schema. You never define types manually. They come from the schema definition.</p>
</li>
<li><p>The <code>$defaultFn</code> on the <code>purchases.id</code> column generates a UUID automatically when you insert a row. The auth tables use text IDs because Better Auth generates its own IDs.</p>
</li>
</ol>
<h3 id="heading-how-to-configure-drizzle-kit">How to Configure Drizzle Kit</h3>
<p>Create <code>drizzle.config.ts</code> at the project root:</p>
<pre><code class="language-typescript">// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/lib/db/schema.ts",
  out: "./drizzle",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
  verbose: true,
  strict: true,
});
</code></pre>
<p>Add these scripts to your <code>package.json</code>:</p>
<pre><code class="language-json">{
  "scripts": {
    "db:generate": "drizzle-kit generate",
    "db:push": "drizzle-kit push",
    "db:migrate": "drizzle-kit migrate",
    "db:studio": "drizzle-kit studio"
  }
}
</code></pre>
<p>Now push your schema to the local database:</p>
<pre><code class="language-bash">bun run db:push
</code></pre>
<p>Drizzle Kit reads your schema file, compares it to the database, and applies any changes. For development, <code>db:push</code> is fast and convenient. For production, you'll use <code>db:generate</code> and <code>db:migrate</code> to create versioned SQL migration files.</p>
<p>You can open Drizzle Studio to inspect your database visually:</p>
<pre><code class="language-bash">bun run db:studio
</code></pre>
<p>This opens a web UI at <code>https://local.drizzle.studio</code> where you can browse tables, run queries, and inspect data.</p>
<h2 id="heading-how-to-build-the-api-with-elysia">How to Build the API with Elysia</h2>
<p>Here's where this stack gets interesting. Instead of running a separate API server, you embed Elysia directly inside TanStack Start. Both your web app and your API live in the same process, share the same types, and deploy as a single unit.</p>
<h3 id="heading-why-elysia-instead-of-express">Why Elysia Instead of Express?</h3>
<p>If you've built Node.js APIs before, you've probably used Express. It is 15 years old and has a massive ecosystem. But Express was designed before TypeScript, before async/await, and before developers expected type safety across the full stack.</p>
<p>Elysia takes a different approach. It was built for TypeScript from day one. Request bodies, response types, and path parameters are all inferred at compile time.</p>
<p>Combined with Eden Treaty (which you'll set up in the next section), your frontend gets full type safety when calling your API. No code generation. No OpenAPI schemas to keep in sync. Just TypeScript inference.</p>
<p>Elysia also includes built-in request validation using its <code>t</code> (TypeBox) schema builder:</p>
<pre><code class="language-typescript">import { Elysia, t } from "elysia";

new Elysia().post(
  "/users",
  ({ body }) =&gt; {
    // body is typed as { name: string, email: string }
    return createUser(body);
  },
  {
    body: t.Object({
      name: t.String(),
      email: t.String(),
    }),
  }
);
</code></pre>
<p>The schema validates at runtime and provides TypeScript types at compile time. One definition serves both purposes.</p>
<h3 id="heading-how-to-define-your-api">How to Define Your API</h3>
<p>Create <code>src/server/api.ts</code>. This is where all your API routes live:</p>
<pre><code class="language-typescript">// src/server/api.ts
import { Elysia, t } from "elysia";
import { eq } from "drizzle-orm";

import { auth } from "@/lib/auth";
import { db, purchases, users } from "@/lib/db";

export const api = new Elysia({ prefix: "/api" })
  .onRequest(({ request }) =&gt; {
    console.log(`[API] \({request.method} \){request.url}`);
  })
  .onError(({ code, error, path }) =&gt; {
    console.error(`[API ERROR] \({code} on \){path}:`, error);
  })
  .get("/health", () =&gt; ({
    status: "ok",
    timestamp: new Date().toISOString(),
  }))
  .get("/me", async ({ request, set }) =&gt; {
    const session = await auth.api.getSession({
      headers: request.headers,
    });

    if (!session) {
      set.status = 401;
      return { error: "Unauthorized" };
    }

    return { user: session.user };
  })
  .get("/payments/status", async ({ request, set }) =&gt; {
    const session = await auth.api.getSession({
      headers: request.headers,
    });

    if (!session) {
      set.status = 401;
      return { error: "Unauthorized" };
    }

    const purchase = await db
      .select()
      .from(purchases)
      .where(eq(purchases.userId, session.user.id))
      .limit(1);

    return {
      userId: session.user.id,
      purchase: purchase[0] ?? null,
    };
  });

export type Api = typeof api;
</code></pre>
<p>That last line is critical. <code>export type Api = typeof api</code> exports the full type signature of your API. Eden Treaty uses this type to generate a fully typed client on the frontend.</p>
<p>You'll see how that works shortly.</p>
<p>Notice the pattern for authenticated endpoints: call <code>auth.api.getSession()</code> with the request headers, check if the session exists, and return a 401 if it does not. This is straightforward and explicit. No decorators, no middleware magic.</p>
<p>The <code>onRequest</code> and <code>onError</code> hooks provide logging for every request. In production, you would replace these with structured logging to your observability platform.</p>
<h3 id="heading-how-to-mount-elysia-in-tanstack-start">How to Mount Elysia in TanStack Start</h3>
<p>TanStack Start uses file-based routing. To handle all API requests with Elysia, create a catch-all route at <code>src/routes/api.$.ts</code>:</p>
<pre><code class="language-typescript">// src/routes/api.$.ts
import { createFileRoute } from "@tanstack/react-router";

import { api } from "../server/api";

const handler = ({ request }: { request: Request }) =&gt; api.fetch(request);

export const Route = createFileRoute("/api/$")({
  server: {
    handlers: {
      GET: handler,
      POST: handler,
      PUT: handler,
      PATCH: handler,
      DELETE: handler,
      OPTIONS: handler,
    },
  },
});
</code></pre>
<p>The <code>$</code> in the filename is TanStack Router's wildcard syntax. This route matches any path starting with <code>/api/</code>, and the <code>server.handlers</code> object maps HTTP methods to your Elysia handler. Every request to <code>/api/*</code> gets forwarded to Elysia's <code>fetch</code> method.</p>
<p>This is the key architectural insight: Elysia is embedded inside TanStack Start. There is no separate API server. Your web app and API share the same process, the same port, and the same deployment.</p>
<p>This eliminates CORS issues, simplifies deployment, and means your API types are directly importable on the frontend.</p>
<p>Test your API by visiting <code>http://localhost:3000/api/health</code>. You should see:</p>
<pre><code class="language-json">{ "status": "ok", "timestamp": "2026-03-28T12:00:00.000Z" }
</code></pre>
<h2 id="heading-how-to-add-type-safe-api-calls-with-eden-treaty">How to Add Type-Safe API Calls with Eden Treaty</h2>
<p><a href="https://elysiajs.com/eden/treaty/overview">Eden Treaty</a> is Elysia's companion client library. It's an end-to-end type-safe HTTP client that mirrors your Elysia API's route structure as a JavaScript object. Instead of writing <code>fetch("/api/users")</code> and manually typing the response, you call <code>api.api.users.get()</code> and get full autocompletion, parameter validation, and return type inference, all derived from your server code at compile time with zero code generation.</p>
<p>This is what makes the stack special. Eden Treaty reads the type exported from your Elysia API and generates a fully typed client. Every endpoint, every parameter, every response shape is inferred at compile time.</p>
<h3 id="heading-how-to-set-up-the-treaty-client">How to Set Up the Treaty Client</h3>
<p>Since Elysia is embedded in your TanStack Start app (same origin), you don't need to pass a URL to the Treaty client. You can create the client directly from the Elysia app instance for server-side usage and use a URL-based client for browser-side usage.</p>
<p>The simplest approach is to create a helper function that returns a treaty client:</p>
<pre><code class="language-typescript">// src/lib/treaty.ts
import { treaty } from "@elysiajs/eden";

import type { Api } from "@/server/api";

// For client-side usage, connect to the same origin
export const api = treaty&lt;Api&gt;(
  typeof window !== "undefined"
    ? window.location.origin
    : (process.env.BETTER_AUTH_URL ?? "http://localhost:3000")
);
</code></pre>
<p>Now you can use <code>api</code> anywhere in your application with full type safety:</p>
<pre><code class="language-typescript">// Calling GET /api/health
const { data } = await api.api.health.get();
// data is typed as { status: string, timestamp: string }

// Calling GET /api/me (authenticated)
const { data: me, error } = await api.api.me.get();
// data is typed as { user: { id: string, email: string, ... } }
// error is typed as { error: string } | null
</code></pre>
<p>Notice how the method chain mirrors your route structure. The <code>/api/health</code> endpoint becomes <code>api.api.health.get()</code>. Path segments become properties, and the HTTP method becomes the final function call.</p>
<p>This is all inferred from the <code>type Api = typeof api</code> export.</p>
<h3 id="heading-how-types-flow-from-server-to-client">How Types Flow from Server to Client</h3>
<p>Here's the full picture of how types flow through the stack:</p>
<pre><code class="language-text">┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│  Drizzle Schema  │     │    Elysia API    │     │   Eden Treaty   │
│  (schema.ts)     │────▶│   (api.ts)       │────▶│   (client)      │
│                  │     │                  │     │                  │
│  type User =     │     │  .get("/me",     │     │  api.api.me     │
│  typeof users    │     │    () =&gt; user)   │     │    .get()       │
│  .$inferSelect   │     │                  │     │    → { user }   │
└─────────────────┘     └─────────────────┘     └─────────────────┘
</code></pre>
<p>First, <strong>Drizzle</strong> infers TypeScript types from your table definitions. The <code>User</code> type comes from the <code>users</code> table schema.</p>
<p>Then <strong>Elysia</strong> uses those types in route handlers. When a handler returns <code>{ user: session.user }</code>, Elysia captures the return type.</p>
<p>Finally, <strong>Eden Treaty</strong> reads the <code>type Api = typeof api</code> export and generates a client where every endpoint is fully typed.</p>
<p>If you add a field to your <code>users</code> table schema, Drizzle's inferred types update. If your Elysia handler returns that new field, Eden Treaty's client types update. If your React component accesses a field that no longer exists, TypeScript catches the error at compile time.</p>
<p>Zero code generation. Zero runtime overhead. Just TypeScript inference doing what it does best.</p>
<h3 id="heading-how-to-handle-errors-with-eden-treaty">How to Handle Errors with Eden Treaty</h3>
<p>Every Eden Treaty call returns a <code>{ data, error }</code> tuple. This isn't a thrown exception. It's a discriminated union that forces you to handle both success and failure cases:</p>
<pre><code class="language-typescript">const { data, error } = await api.api.me.get();

if (error) {
  // error is typed based on what your Elysia handler can return
  console.error("Failed to fetch user:", error);
  return null;
}

// data is now narrowed to the success type
console.log(data.user.email);
</code></pre>
<p>This pattern eliminates the "forgot to handle the error" class of bugs that are common with <code>fetch</code> or Axios, where errors are thrown and easily missed. With Eden Treaty, the TypeScript compiler reminds you.</p>
<h3 id="heading-how-to-use-eden-treaty-in-route-loaders">How to Use Eden Treaty in Route Loaders</h3>
<p>TanStack Start routes have <code>loader</code> functions that run on the server during SSR and on the client during navigation. You can use Eden Treaty in these loaders to fetch data before the page renders:</p>
<pre><code class="language-typescript">// src/routes/_authenticated/dashboard.tsx
import { createFileRoute } from "@tanstack/react-router";

import { api } from "@/lib/treaty";

export const Route = createFileRoute("/_authenticated/dashboard")({
  loader: async () =&gt; {
    const { data } = await api.api.payments.status.get();
    return { purchase: data?.purchase ?? null };
  },
  component: DashboardPage,
});

function DashboardPage() {
  const { purchase } = Route.useLoaderData();

  return (
    &lt;div&gt;
      &lt;h1&gt;Dashboard&lt;/h1&gt;
      {purchase ? (
        &lt;p&gt;Your plan: {purchase.tier}&lt;/p&gt;
      ) : (
        &lt;p&gt;No active plan.&lt;/p&gt;
      )}
    &lt;/div&gt;
  );
}
</code></pre>
<p>The <code>loader</code> runs before the component renders, so the page never shows a loading spinner for its initial data. <code>Route.useLoaderData()</code> returns fully typed data based on what the loader returns. Change the loader's return type, and TypeScript catches mismatches in the component.</p>
<h2 id="heading-how-to-add-authentication-with-better-auth">How to Add Authentication with Better Auth</h2>
<p>Every SaaS needs authentication. In this tutorial, you'll use Better Auth with GitHub OAuth. Better Auth is a framework-agnostic auth library that works natively with Drizzle and has first-class support for TanStack Start.</p>
<h3 id="heading-how-to-create-a-github-oauth-app">How to Create a GitHub OAuth App</h3>
<p>Before writing any code, create a GitHub OAuth application:</p>
<ol>
<li><p>Go to <a href="https://github.com/settings/developers">GitHub Developer Settings</a></p>
</li>
<li><p>Click "New OAuth App"</p>
</li>
<li><p>Set the Homepage URL to <code>http://localhost:3000</code></p>
</li>
<li><p>Set the Authorization callback URL to <code>http://localhost:3000/api/auth/callback/github</code></p>
</li>
<li><p>Click "Register application"</p>
</li>
<li><p>Copy the Client ID and generate a Client Secret</p>
</li>
</ol>
<p>Add these to a <code>.env</code> file at the project root:</p>
<pre><code class="language-bash"># .env
DATABASE_URL=postgres://postgres:postgres@db.localtest.me:5432/my_saas
BETTER_AUTH_SECRET=your-random-32-character-string-here
BETTER_AUTH_URL=http://localhost:3000
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
</code></pre>
<p>Generate a random secret for <code>BETTER_AUTH_SECRET</code>:</p>
<pre><code class="language-bash">openssl rand -base64 32
</code></pre>
<h3 id="heading-how-to-configure-the-auth-server">How to Configure the Auth Server</h3>
<p>Create <code>src/lib/auth/index.ts</code>. This is the server-side auth configuration:</p>
<pre><code class="language-typescript">// src/lib/auth/index.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { tanstackStartCookies } from "better-auth/tanstack-start";

import * as schema from "@/lib/db";
import { db } from "@/lib/db";

const isDev = process.env.NODE_ENV !== "production";
const baseURL = process.env.BETTER_AUTH_URL ?? "http://localhost:3000";

export const auth = betterAuth({
  baseURL,
  database: drizzleAdapter(db, {
    provider: "pg",
    usePlural: true,
    schema: {
      users: schema.users,
      sessions: schema.sessions,
      accounts: schema.accounts,
      verifications: schema.verifications,
    },
  }),

  socialProviders: {
    github: {
      clientId: process.env.GITHUB_CLIENT_ID ?? "",
      clientSecret: process.env.GITHUB_CLIENT_SECRET ?? "",
    },
  },

  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
    updateAge: 60 * 60 * 24,      // refresh daily
    cookieCache: {
      enabled: true,
      maxAge: 5 * 60, // 5 minutes
    },
  },

  trustedOrigins: isDev
    ? ["http://localhost:3000"]
    : [baseURL],

  plugins: [tanstackStartCookies()],
});

export type Auth = typeof auth;
export type Session = typeof auth.$Infer.Session;
</code></pre>
<p>Key details in this configuration:</p>
<ul>
<li><p><code>drizzleAdapter</code> connects Better Auth to your Drizzle database. The <code>usePlural: true</code> option tells it your tables are named <code>users</code> (not <code>user</code>), <code>sessions</code> (not <code>session</code>), and so on.</p>
</li>
<li><p><code>tanstackStartCookies()</code> is a plugin that handles cookie management for TanStack Start's SSR. Without this, sessions won't persist correctly during server-side rendering.</p>
</li>
<li><p><code>cookieCache</code> stores session data in the cookie for 5 minutes, reducing database lookups on every request.</p>
</li>
</ul>
<h3 id="heading-how-to-configure-the-auth-client">How to Configure the Auth Client</h3>
<p>Create <code>src/lib/auth/client.ts</code> for the browser-side auth client:</p>
<pre><code class="language-typescript">// src/lib/auth/client.ts
import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient({
  baseURL: "",
});

export const { signIn, signOut, useSession } = authClient;
</code></pre>
<p>The <code>baseURL</code> is an empty string because Elysia is embedded in your TanStack Start app. Auth requests go to <code>/api/auth/*</code> on the same origin. No separate auth server needed.</p>
<h3 id="heading-how-to-mount-auth-routes">How to Mount Auth Routes</h3>
<p>Better Auth needs to handle requests at <code>/api/auth/*</code>. Since Elysia handles all <code>/api/*</code> routes, you mount Better Auth's handler inside Elysia.</p>
<p>Add this to your <code>src/server/api.ts</code>:</p>
<pre><code class="language-typescript">// In src/server/api.ts, add Better Auth's handler
export const api = new Elysia({ prefix: "/api" })
  // Mount Better Auth to handle /api/auth/* routes
  .mount(auth.handler)
  // ... rest of your routes
</code></pre>
<p>The <code>.mount(auth.handler)</code> call tells Elysia to forward any request matching Better Auth's routes to the auth handler. This covers login, logout, session management, and OAuth callbacks.</p>
<h3 id="heading-how-to-protect-routes">How to Protect Routes</h3>
<p>TanStack Start uses layout routes to protect groups of pages. Create <code>src/routes/_authenticated.tsx</code>:</p>
<pre><code class="language-typescript">// src/routes/_authenticated.tsx
import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";
import { createServerFn } from "@tanstack/react-start";
import { getRequestHeaders } from "@tanstack/react-start/server";

import { auth } from "@/lib/auth";

const getCurrentUser = createServerFn().handler(async () =&gt; {
  const rawHeaders = getRequestHeaders();
  const headers = new Headers(rawHeaders as HeadersInit);
  const session = await auth.api.getSession({ headers });
  return session?.user ?? null;
});

export const Route = createFileRoute("/_authenticated")({
  beforeLoad: async ({ location }) =&gt; {
    const user = await getCurrentUser();

    if (!user) {
      throw redirect({
        to: "/login",
        search: { redirect: location.pathname },
      });
    }

    return { user };
  },
  component: AuthenticatedLayout,
});

function AuthenticatedLayout() {
  return &lt;Outlet /&gt;;
}
</code></pre>
<p>The <code>_authenticated</code> prefix (with underscore) makes this a layout route in TanStack Router. Any route nested inside <code>src/routes/_authenticated/</code> will run the <code>beforeLoad</code> check first. If the user isn't logged in, they get redirected to <code>/login</code> with a redirect parameter so they return to the original page after signing in.</p>
<p>The <code>createServerFn</code> runs on the server during SSR. It reads the request cookies, checks for a valid session, and returns the user. This means your auth check happens server-side before any HTML is sent to the browser.</p>
<p>Now any file you create under <code>src/routes/_authenticated/</code> is automatically protected. For example, <code>src/routes/_authenticated/dashboard.tsx</code> requires authentication.</p>
<h3 id="heading-how-to-build-the-login-page">How to Build the Login Page</h3>
<p>Create a login page at <code>src/routes/login.tsx</code>:</p>
<pre><code class="language-typescript">// src/routes/login.tsx
import { createFileRoute } from "@tanstack/react-router";
import { useState } from "react";
import { z } from "zod";

import { signIn } from "@/lib/auth/client";

const searchSchema = z.object({
  redirect: z.string().optional(),
});

export const Route = createFileRoute("/login")({
  validateSearch: searchSchema,
  component: LoginPage,
});

function LoginPage() {
  const { redirect: redirectTo } = Route.useSearch();
  const [isLoading, setIsLoading] = useState(false);

  const handleGitHubLogin = async () =&gt; {
    setIsLoading(true);
    const callbackURL = redirectTo
      ? `\({window.location.origin}\){redirectTo}`
      : `${window.location.origin}/dashboard`;

    await signIn.social({
      provider: "github",
      callbackURL,
    });
  };

  return (
    &lt;div className="flex min-h-screen items-center justify-center"&gt;
      &lt;div className="w-full max-w-md rounded-lg border p-8"&gt;
        &lt;h1 className="mb-6 text-2xl font-bold"&gt;Sign In&lt;/h1&gt;
        &lt;button
          onClick={handleGitHubLogin}
          disabled={isLoading}
          className="w-full rounded-md bg-gray-900 px-4 py-3 text-white"
        &gt;
          {isLoading ? "Signing in..." : "Sign in with GitHub"}
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>TanStack Router's <code>validateSearch</code> validates query parameters with Zod. The <code>redirect</code> parameter is typed as an optional string, and <code>Route.useSearch()</code> returns a type-safe object. No manual parsing needed.</p>
<h3 id="heading-how-to-add-login-redirect-middleware">How to Add Login Redirect Middleware</h3>
<p>You also want to redirect authenticated users away from the login page. Create the entry point at <code>src/start.ts</code>:</p>
<pre><code class="language-typescript">// src/start.ts
import { redirect } from "@tanstack/react-router";
import { createMiddleware, createStart } from "@tanstack/react-start";
import { getRequestHeaders, getRequestUrl } from "@tanstack/react-start/server";

import { auth } from "@/lib/auth";

const authMiddleware = createMiddleware({ type: "request" }).server(
  async ({ next }) =&gt; {
    const rawHeaders = getRequestHeaders();
    const headers = new Headers(rawHeaders as HeadersInit);
    const url = getRequestUrl();

    if (url.pathname !== "/login") {
      return next();
    }

    const session = await auth.api.getSession({ headers });

    if (session?.user) {
      const redirectTo = url.searchParams.get("redirect");
      throw redirect({
        to: redirectTo || "/dashboard",
      });
    }

    return next();
  }
);

export const startInstance = createStart(() =&gt; ({
  requestMiddleware: [authMiddleware],
}));
</code></pre>
<p>This middleware runs on every request. If the user is already authenticated and visits <code>/login</code>, they get redirected to the dashboard (or to whatever page they originally wanted to reach).</p>
<h2 id="heading-how-to-build-a-complete-feature-the-four-layer-pattern">How to Build a Complete Feature (The Four-Layer Pattern)</h2>
<p>Now that you have a database, API, type-safe client, and authentication, it's time to build a real feature. Every feature in this architecture follows the same four-layer pattern:</p>
<img src="https://cdn.hashnode.com/uploads/covers/69a694d8d4dc9b42434c218f/2e658c33-30fa-49ea-b5fc-50428d336cc4.png" alt="The four-layer feature pattern used throughout the tutorial: Layer 1 Schema defines the data structure, Layer 2 API exposes CRUD operations, Layer 3 Hooks connects React to the API, and Layer 4 UI renders and handles user interactions" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>Once you understand this pattern, adding features becomes mechanical. Let's walk through building a complete purchase status feature that lets authenticated users check their purchase history.</p>
<h3 id="heading-layer-1-schema">Layer 1: Schema</h3>
<p>You already defined the <code>purchases</code> table in your schema earlier. For reference:</p>
<pre><code class="language-typescript">// src/lib/db/schema.ts
export const purchases = pgTable("purchases", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() =&gt; crypto.randomUUID()),
  userId: text("user_id")
    .notNull()
    .references(() =&gt; users.id, { onDelete: "cascade" }),
  stripeCheckoutSessionId: text("stripe_checkout_session_id")
    .notNull()
    .unique(),
  stripeCustomerId: text("stripe_customer_id"),
  stripePaymentIntentId: text("stripe_payment_intent_id"),
  tier: purchaseTierEnum("tier").notNull(),
  status: purchaseStatusEnum("status").notNull().default("completed"),
  amount: integer("amount").notNull(),
  currency: text("currency").notNull().default("usd"),
  purchasedAt: timestamp("purchased_at").notNull().defaultNow(),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});
</code></pre>
<p>If you're adding a new feature, this is where you start. Define the table, run <code>bun run db:push</code>, and move to Layer 2.</p>
<h3 id="heading-layer-2-api">Layer 2: API</h3>
<p>Create an API route module at <code>src/server/routes/purchases.ts</code>:</p>
<pre><code class="language-typescript">// src/server/routes/purchases.ts
import { eq } from "drizzle-orm";
import { Elysia } from "elysia";

import { auth } from "@/lib/auth";
import { db, purchases } from "@/lib/db";

export const purchasesRoute = new Elysia({ prefix: "/purchases" })
  .get("/status", async ({ request, set }) =&gt; {
    const session = await auth.api.getSession({
      headers: request.headers,
    });

    if (!session?.user) {
      set.status = 401;
      return { error: "Unauthorized" };
    }

    const purchase = await db
      .select()
      .from(purchases)
      .where(eq(purchases.userId, session.user.id))
      .limit(1);

    return purchase[0] ?? null;
  });
</code></pre>
<p>Then register this route module in your main API file:</p>
<pre><code class="language-typescript">// src/server/api.ts
import { purchasesRoute } from "./routes/purchases";

export const api = new Elysia({ prefix: "/api" })
  .mount(auth.handler)
  .use(purchasesRoute)
  // ... other routes
</code></pre>
<p>The <code>.use()</code> method composes Elysia instances. Each route module is an independent Elysia instance with its own prefix, and <code>use</code> merges them into the main app. Eden Treaty sees the full composed type, so your client automatically knows about the new endpoints.</p>
<h3 id="heading-layer-3-hooks">Layer 3: Hooks</h3>
<p>Create a custom hook that connects your React components to the API:</p>
<pre><code class="language-typescript">// src/hooks/use-purchase-status.ts
import { useQuery } from "@tanstack/react-query";

import { api } from "@/lib/treaty";

export function usePurchaseStatus() {
  return useQuery({
    queryKey: ["purchase-status"],
    queryFn: async () =&gt; {
      const { data, error } = await api.api.purchases.status.get();
      if (error) throw new Error("Failed to fetch purchase status");
      return data;
    },
  });
}
</code></pre>
<p>TanStack Query handles caching, refetching, loading states, and error states. The <code>queryKey</code> identifies this data in the cache. If multiple components call <code>usePurchaseStatus()</code>, only one network request is made.</p>
<p>For mutations (creating, updating, or deleting data), use <code>useMutation</code>:</p>
<pre><code class="language-typescript">// src/hooks/use-checkout.ts
import { useMutation } from "@tanstack/react-query";

import { api } from "@/lib/treaty";

export function useCheckout() {
  return useMutation({
    mutationFn: async () =&gt; {
      const { data, error } = await api.api.payments.checkout.post();
      if (error) throw new Error("Failed to create checkout session");
      return data;
    },
    onSuccess: (data) =&gt; {
      // Redirect to Stripe Checkout
      if (data?.url) {
        window.location.href = data.url;
      }
    },
  });
}
</code></pre>
<h3 id="heading-layer-4-ui">Layer 4: UI</h3>
<p>Use the hooks in your React components:</p>
<pre><code class="language-tsx">// src/components/purchase-status.tsx
import { usePurchaseStatus } from "@/hooks/use-purchase-status";

export function PurchaseStatus() {
  const { data: purchase, isLoading, error } = usePurchaseStatus();

  if (isLoading) {
    return &lt;div&gt;Loading...&lt;/div&gt;;
  }

  if (error) {
    return &lt;div&gt;Failed to load purchase status.&lt;/div&gt;;
  }

  if (!purchase) {
    return (
      &lt;div className="rounded-lg border p-6"&gt;
        &lt;h2 className="text-lg font-semibold"&gt;No Active Purchase&lt;/h2&gt;
        &lt;p className="mt-2 text-gray-600"&gt;
          You have not purchased a plan yet.
        &lt;/p&gt;
      &lt;/div&gt;
    );
  }

  return (
    &lt;div className="rounded-lg border p-6"&gt;
      &lt;h2 className="text-lg font-semibold"&gt;
        {purchase.tier.charAt(0).toUpperCase() + purchase.tier.slice(1)} Plan
      &lt;/h2&gt;
      &lt;p className="mt-2 text-gray-600"&gt;
        Status: {purchase.status}
      &lt;/p&gt;
      &lt;p className="text-sm text-gray-500"&gt;
        Purchased on{" "}
        {new Date(purchase.purchasedAt).toLocaleDateString()}
      &lt;/p&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<p>That's the complete four-layer pattern. The schema defines the data. The API exposes it. Hooks connect React to the API. The UI renders the result. Every feature you add follows these same four steps.</p>
<h3 id="heading-how-the-layers-connect">How the Layers Connect</h3>
<p>Here's the full picture of how data flows through the four layers for a read operation:</p>
<pre><code class="language-text">User clicks "Dashboard"
  → TanStack Router triggers the route loader
    → Loader calls api.api.purchases.status.get() via Eden Treaty
      → Elysia receives GET /api/purchases/status
        → Handler calls auth.api.getSession() to verify the user
        → Handler queries db.select().from(purchases) via Drizzle
        → Handler returns { purchase } with inferred types
      → Eden Treaty receives typed response
    → Loader returns typed data
  → Component renders with Route.useLoaderData()
</code></pre>
<p>For a write operation (creating a new resource), the flow is similar but uses a mutation:</p>
<pre><code class="language-text">User clicks "Buy Now"
  → onClick calls checkout.mutate() from useMutation hook
    → mutationFn calls api.api.payments.checkout.post() via Eden Treaty
      → Elysia receives POST /api/payments/checkout
        → Handler creates a Stripe checkout session
        → Handler returns { url }
      → Eden Treaty receives typed response
    → onSuccess redirects to Stripe Checkout
</code></pre>
<h3 id="heading-how-to-add-a-second-feature">How to Add a Second Feature</h3>
<p>To cement the pattern, let's walk through adding a user profile update feature. This shows all four layers for a write operation.</p>
<p><strong>Layer 1: Schema.</strong> The <code>users</code> table already has a <code>name</code> field you can update. No schema change needed.</p>
<p><strong>Layer 2: API.</strong> Add a PATCH endpoint:</p>
<pre><code class="language-typescript">// In src/server/api.ts
.patch(
  "/me",
  async ({ request, body, set }) =&gt; {
    const session = await auth.api.getSession({
      headers: request.headers,
    });

    if (!session) {
      set.status = 401;
      return { error: "Unauthorized" };
    }

    const [updatedUser] = await db
      .update(users)
      .set({
        name: body.name,
        updatedAt: new Date(),
      })
      .where(eq(users.id, session.user.id))
      .returning();

    return { user: updatedUser };
  },
  {
    body: t.Object({
      name: t.String({ minLength: 1, maxLength: 100 }),
    }),
  },
)
</code></pre>
<p>The <code>body</code> option validates the request body at runtime and provides TypeScript types at compile time. If someone sends a request without a <code>name</code> field, Elysia returns a 400 error automatically. You don't write any validation logic yourself.</p>
<p><strong>Layer 3: Hooks.</strong> Create a mutation hook:</p>
<pre><code class="language-typescript">// src/hooks/use-update-profile.ts
import { useMutation, useQueryClient } from "@tanstack/react-query";

import { api } from "@/lib/treaty";

export function useUpdateProfile() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (data: { name: string }) =&gt; {
      const { data: result, error } = await api.api.me.patch(data);
      if (error) throw new Error("Failed to update profile");
      return result;
    },
    onSuccess: () =&gt; {
      // Invalidate any queries that depend on user data
      queryClient.invalidateQueries({ queryKey: ["me"] });
    },
  });
}
</code></pre>
<p>The <code>onSuccess</code> callback invalidates the cache for user-related queries. This means any component displaying user data will automatically refetch and show the updated name.</p>
<p><strong>Layer 4: UI.</strong> Use the hook in a form component:</p>
<pre><code class="language-tsx">// src/components/profile-form.tsx
import { useState } from "react";

import { useUpdateProfile } from "@/hooks/use-update-profile";

export function ProfileForm({ currentName }: { currentName: string }) {
  const [name, setName] = useState(currentName);
  const updateProfile = useUpdateProfile();

  const handleSubmit = (e: React.FormEvent) =&gt; {
    e.preventDefault();
    updateProfile.mutate({ name });
  };

  return (
    &lt;form onSubmit={handleSubmit}&gt;
      &lt;label htmlFor="name" className="block text-sm font-medium"&gt;
        Display Name
      &lt;/label&gt;
      &lt;input
        id="name"
        type="text"
        value={name}
        onChange={(e) =&gt; setName(e.target.value)}
        className="mt-1 block w-full rounded-md border px-3 py-2"
      /&gt;
      &lt;button
        type="submit"
        disabled={updateProfile.isPending}
        className="mt-4 rounded-md bg-blue-600 px-4 py-2 text-white"
      &gt;
        {updateProfile.isPending ? "Saving..." : "Save"}
      &lt;/button&gt;
      {updateProfile.isError &amp;&amp; (
        &lt;p className="mt-2 text-sm text-red-600"&gt;
          Failed to update profile. Please try again.
        &lt;/p&gt;
      )}
    &lt;/form&gt;
  );
}
</code></pre>
<p>Four layers, second feature. The pattern is identical every time.</p>
<p>The pattern is deliberately repetitive. Repetition is a feature, not a bug. When every feature follows the same structure, you always know where to look.</p>
<p>New code goes in predictable places. And if you use an AI coding assistant, it can learn this pattern from your codebase and generate all four layers for new features.</p>
<h2 id="heading-how-to-add-payments-with-stripe">How to Add Payments with Stripe</h2>
<p>Most SaaS applications need to collect payments. You'll integrate Stripe for one-time purchases using Stripe Checkout. The key architectural decision is handling webhooks reliably using background jobs, which you'll add in the next section.</p>
<h3 id="heading-how-to-set-up-stripe">How to Set Up Stripe</h3>
<p>Create <code>src/lib/payments/index.ts</code>:</p>
<pre><code class="language-typescript">// src/lib/payments/index.ts
import Stripe from "stripe";

let stripeClient: Stripe | null = null;

function getStripe(): Stripe {
  if (!stripeClient) {
    const secretKey = process.env.STRIPE_SECRET_KEY;
    if (!secretKey) {
      throw new Error(
        "STRIPE_SECRET_KEY is not set. Payment functionality is unavailable."
      );
    }
    stripeClient = new Stripe(secretKey);
  }
  return stripeClient;
}

// Lazy-initialized proxy so imports don't crash without env vars
export const stripe = new Proxy({} as Stripe, {
  get(_, prop) {
    return Reflect.get(getStripe(), prop);
  },
});

export async function createOneTimeCheckoutSession(params: {
  priceId: string;
  successUrl: string;
  cancelUrl: string;
  metadata: Record&lt;string, string&gt;;
  customerEmail?: string;
  couponId?: string;
}) {
  const client = getStripe();

  const session = await client.checkout.sessions.create({
    mode: "payment",
    line_items: [{ price: params.priceId, quantity: 1 }],
    success_url: params.successUrl,
    cancel_url: params.cancelUrl,
    metadata: params.metadata,
    ...(params.customerEmail &amp;&amp; {
      customer_email: params.customerEmail,
    }),
    ...(params.couponId
      ? { discounts: [{ coupon: params.couponId }] }
      : { allow_promotion_codes: true }),
  });

  return session;
}

export async function retrieveCheckoutSession(sessionId: string) {
  const client = getStripe();
  return client.checkout.sessions.retrieve(sessionId);
}

export async function constructWebhookEvent(
  payload: string | Buffer,
  signature: string
) {
  const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
  if (!webhookSecret) {
    throw new Error("STRIPE_WEBHOOK_SECRET is not set");
  }
  const client = getStripe();
  return client.webhooks.constructEventAsync(payload, signature, webhookSecret);
}
</code></pre>
<p>The <code>Proxy</code> pattern for the Stripe client is a production technique. It lazily initializes the Stripe SDK so your module can be imported without crashing if the <code>STRIPE_SECRET_KEY</code> environment variable is missing. This is useful during builds and in environments where not every service is configured.</p>
<h3 id="heading-how-to-create-the-checkout-endpoint">How to Create the Checkout Endpoint</h3>
<p>Add a checkout endpoint to your API:</p>
<pre><code class="language-typescript">// In src/server/api.ts
.post("/payments/checkout", async ({ set }) =&gt; {
  const priceId = process.env.STRIPE_PRO_PRICE_ID;

  if (!priceId) {
    set.status = 500;
    return { error: "Price not configured" };
  }

  const baseUrl = process.env.BETTER_AUTH_URL ?? "http://localhost:3000";

  const checkoutSession = await createOneTimeCheckoutSession({
    priceId,
    successUrl: `${baseUrl}/dashboard?purchase=success&amp;session_id={CHECKOUT_SESSION_ID}`,
    cancelUrl: `${baseUrl}/pricing`,
    metadata: { tier: "pro" },
  });

  return { url: checkoutSession.url };
})
</code></pre>
<p>The <code>{CHECKOUT_SESSION_ID}</code> placeholder is a Stripe template variable. Stripe replaces it with the actual session ID when redirecting the user back to your app.</p>
<h3 id="heading-how-to-handle-webhooks">How to Handle Webhooks</h3>
<p>Stripe sends webhook events when payments are processed. Your webhook handler needs to verify the signature, parse the event, and process it.</p>
<p>Here's the critical design decision: don't do heavy processing inside the webhook handler. Stripe expects a response within a few seconds. If your handler takes too long, Stripe will retry the webhook, potentially causing duplicate processing.</p>
<p>Instead, use the "webhook receives, background job processes" pattern:</p>
<pre><code class="language-typescript">// In src/server/api.ts
.post("/payments/webhook", async ({ request, set }) =&gt; {
  const body = await request.text();
  const sig = request.headers.get("stripe-signature");

  if (!sig) {
    set.status = 400;
    return { error: "Missing signature" };
  }

  try {
    const event = await constructWebhookEvent(body, sig);
    console.log(`[Webhook] Received ${event.type}`);

    if (event.type === "charge.refunded") {
      const charge = event.data.object as {
        id: string;
        payment_intent: string;
        amount: number;
        amount_refunded: number;
        currency: string;
      };
      await inngest.send({
        name: "stripe/charge.refunded",
        data: {
          chargeId: charge.id,
          paymentIntentId: charge.payment_intent,
          amountRefunded: charge.amount_refunded,
          originalAmount: charge.amount,
          currency: charge.currency,
        },
      });
    }

    return { received: true };
  } catch (error) {
    console.error("[Webhook] Stripe verification failed:", error);
    set.status = 400;
    return { error: "Webhook verification failed" };
  }
})
</code></pre>
<p>The webhook handler does three things: verifies the signature, identifies the event type, and forwards the data to Inngest for background processing. It responds immediately with <code>{ received: true }</code>. The actual business logic (sending emails, granting access, updating records) happens in the background job, which you'll build next.</p>
<h3 id="heading-how-to-claim-purchases-on-the-frontend">How to Claim Purchases on the Frontend</h3>
<p>After a successful checkout, Stripe redirects the user back to your app with a session ID. You need an endpoint that claims the purchase by verifying the session and creating a database record:</p>
<pre><code class="language-typescript">// In src/server/api.ts
.post(
  "/purchases/claim",
  async ({ body, request, set }) =&gt; {
    const session = await auth.api.getSession({
      headers: request.headers,
    });

    if (!session) {
      set.status = 401;
      return { error: "Unauthorized" };
    }

    const { sessionId } = body;

    // Check if already claimed (idempotency)
    const existing = await db
      .select()
      .from(purchases)
      .where(eq(purchases.stripeCheckoutSessionId, sessionId))
      .limit(1);

    if (existing[0]) {
      return { success: true, alreadyClaimed: true, tier: existing[0].tier };
    }

    // Verify payment with Stripe
    const stripeSession = await retrieveCheckoutSession(sessionId);

    if (stripeSession.payment_status !== "paid") {
      set.status = 400;
      return { error: "Payment not completed" };
    }

    const tier = (stripeSession.metadata?.tier ?? "pro") as "pro";

    // Create purchase record
    await db.insert(purchases).values({
      userId: session.user.id,
      stripeCheckoutSessionId: sessionId,
      stripeCustomerId:
        typeof stripeSession.customer === "string"
          ? stripeSession.customer
          : stripeSession.customer?.id ?? null,
      stripePaymentIntentId:
        typeof stripeSession.payment_intent === "string"
          ? stripeSession.payment_intent
          : stripeSession.payment_intent?.id ?? null,
      tier,
      status: "completed",
      amount: stripeSession.amount_total ?? 0,
      currency: stripeSession.currency ?? "usd",
    });

    // Trigger background processing
    await inngest.send({
      name: "purchase/completed",
      data: {
        userId: session.user.id,
        tier,
        sessionId,
      },
    });

    return { success: true, tier };
  },
  {
    body: t.Object({
      sessionId: t.String(),
    }),
  }
)
</code></pre>
<p>Notice the idempotency check at the top. If the user refreshes the success page or the frontend retries the claim request, the endpoint returns the existing purchase instead of creating a duplicate.</p>
<p>This is essential for payment flows. You never want to accidentally charge someone twice or create duplicate records.</p>
<p>The <code>inngest.send()</code> call triggers background processing for the purchase. That's where you send confirmation emails, grant access to resources, track analytics events, and perform any other post-purchase work.</p>
<h3 id="heading-how-to-test-payments-locally">How to Test Payments Locally</h3>
<p>Install the Stripe CLI and forward webhooks to your local server:</p>
<pre><code class="language-bash"># Install Stripe CLI (macOS)
brew install stripe/stripe-cli/stripe

# Login to Stripe
stripe login

# Forward webhooks to your local server
stripe listen --forward-to localhost:3000/api/payments/webhook
</code></pre>
<p>The Stripe CLI gives you a webhook signing secret that starts with <code>whsec_</code>. Add it to your <code>.env</code>:</p>
<pre><code class="language-bash">STRIPE_WEBHOOK_SECRET=whsec_your-local-webhook-secret
</code></pre>
<p>Create a test product and price in your Stripe dashboard (or use the Stripe CLI), then add the price ID to your <code>.env</code>:</p>
<pre><code class="language-bash">STRIPE_SECRET_KEY=sk_test_your-test-secret-key
STRIPE_PRO_PRICE_ID=price_your-test-price-id
</code></pre>
<h2 id="heading-how-to-add-background-jobs-with-inngest">How to Add Background Jobs with Inngest</h2>
<p>Background jobs are critical for any SaaS. You use them for processing webhooks, sending emails, granting access to resources, and any work that shouldn't block your API response. Inngest provides durable, retry-able functions with built-in checkpointing.</p>
<h3 id="heading-why-background-jobs-matter">Why Background Jobs Matter</h3>
<p>Consider what happens when someone purchases your SaaS product:</p>
<ol>
<li><p>Verify the payment with Stripe</p>
</li>
<li><p>Create a purchase record in the database</p>
</li>
<li><p>Send a confirmation email to the customer</p>
</li>
<li><p>Send a notification email to the admin</p>
</li>
<li><p>Grant access to a private GitHub repository</p>
</li>
<li><p>Track the purchase event in your analytics platform</p>
</li>
<li><p>Schedule a follow-up email sequence</p>
</li>
</ol>
<p>If you try to do all of this inside an API endpoint, several things can go wrong. The email service might be down. The GitHub API might rate-limit you. Your analytics call might time out.</p>
<p>Any failure means the user sees an error, and you have to figure out which steps completed and which did not.</p>
<p>Inngest solves this with durable execution. Each step is checkpointed. If step 3 fails, Inngest retries step 3 without re-running steps 1 and 2.</p>
<p>If the entire function fails, Inngest retries the whole thing. You get at-least-once execution with automatic deduplication.</p>
<h3 id="heading-how-to-set-up-inngest">How to Set Up Inngest</h3>
<p>Create the Inngest client at <code>src/lib/jobs/client.ts</code>:</p>
<pre><code class="language-typescript">// src/lib/jobs/client.ts
import { Inngest } from "inngest";

export const inngest = new Inngest({
  id: "my-saas",
});
</code></pre>
<h3 id="heading-how-to-write-your-first-inngest-function">How to Write Your First Inngest Function</h3>
<p>Create <code>src/lib/jobs/functions/stripe.ts</code> with the purchase completion handler:</p>
<pre><code class="language-typescript">// src/lib/jobs/functions/stripe.ts
import { eq } from "drizzle-orm";

import { inngest } from "../client";
import { db, purchases, users } from "@/lib/db";

export const handlePurchaseCompleted = inngest.createFunction(
  {
    id: "purchase-completed",
    triggers: [{ event: "purchase/completed" }],
  },
  async ({ event, step }) =&gt; {
    const { userId, tier, sessionId } = event.data as {
      userId: string;
      tier: string;
      sessionId: string;
    };

    // Step 1: Look up user and purchase details
    const { user, purchase } = await step.run(
      "lookup-user-and-purchase",
      async () =&gt; {
        const userResult = await db
          .select({
            id: users.id,
            email: users.email,
            name: users.name,
          })
          .from(users)
          .where(eq(users.id, userId))
          .limit(1);

        const foundUser = userResult[0];
        if (!foundUser) {
          throw new Error(`User not found: ${userId}`);
        }

        const purchaseResult = await db
          .select({
            amount: purchases.amount,
            currency: purchases.currency,
          })
          .from(purchases)
          .where(eq(purchases.stripeCheckoutSessionId, sessionId))
          .limit(1);

        return {
          user: foundUser,
          purchase: purchaseResult[0] ?? {
            amount: 0,
            currency: "usd",
          },
        };
      }
    );

    // Step 2: Send purchase confirmation email
    await step.run("send-purchase-confirmation", async () =&gt; {
      // Send email using your email service (Resend, SendGrid, and so on)
      console.log(
        `Sending purchase confirmation to ${user.email}`
      );
      // await sendEmail({
      //   to: user.email,
      //   subject: "Your purchase is confirmed!",
      //   template: PurchaseConfirmationEmail,
      // });
    });

    // Step 3: Send admin notification
    await step.run("send-admin-notification", async () =&gt; {
      const adminEmail = process.env.ADMIN_EMAIL;
      if (!adminEmail) return;

      console.log(
        `Notifying admin about purchase from ${user.email}`
      );
      // await sendEmail({
      //   to: adminEmail,
      //   subject: `New sale: ${user.email}`,
      //   template: AdminNotificationEmail,
      // });
    });

    // Step 4: Update purchase record
    await step.run("update-purchase-record", async () =&gt; {
      await db
        .update(purchases)
        .set({ updatedAt: new Date() })
        .where(eq(purchases.stripeCheckoutSessionId, sessionId));
    });

    return { success: true, userId, tier };
  }
);

export const stripeFunctions = [handlePurchaseCompleted];
</code></pre>
<p>Each <code>step.run()</code> is a checkpoint. If the function fails after step 2, Inngest retries from step 3, not from the beginning. The results of completed steps are cached.</p>
<h3 id="heading-how-to-register-your-functions">How to Register Your Functions</h3>
<p>Create an index file that collects all your functions:</p>
<pre><code class="language-typescript">// src/lib/jobs/functions/index.ts
import { stripeFunctions } from "./stripe";

export const functions = [...stripeFunctions];
</code></pre>
<p>And a barrel export:</p>
<pre><code class="language-typescript">// src/lib/jobs/index.ts
export { inngest } from "./client";
export { functions } from "./functions";
</code></pre>
<h3 id="heading-how-to-connect-inngest-to-your-api">How to Connect Inngest to Your API</h3>
<p>Mount the Inngest handler in your Elysia API. Add this to <code>src/server/api.ts</code>:</p>
<pre><code class="language-typescript">// src/server/api.ts
import { serve } from "inngest/bun";

import { inngest, functions } from "@/lib/jobs";

const inngestHandler = serve({
  client: inngest,
  functions,
});

export const api = new Elysia({ prefix: "/api" })
  // Inngest endpoint - handles function registration and execution
  .all("/inngest", async (ctx) =&gt; {
    return inngestHandler(ctx.request);
  })
  // ... rest of your routes
</code></pre>
<p>The <code>.all("/inngest")</code> route handles both GET (for function registration) and POST (for function execution) requests from Inngest.</p>
<h3 id="heading-how-to-run-inngest-locally">How to Run Inngest Locally</h3>
<p>Inngest provides a dev server that runs locally and provides a dashboard for monitoring your functions:</p>
<pre><code class="language-bash">npx inngest-cli@latest dev -u http://localhost:3000/api/inngest --no-discovery
</code></pre>
<p>This starts the Inngest dev server at <code>http://localhost:8288</code>. Open that URL in your browser to see a dashboard showing your registered functions, event history, and function execution logs.</p>
<p>The <code>-u</code> flag tells Inngest where your app is running. The <code>--no-discovery</code> flag disables automatic app discovery, which is more reliable for local development.</p>
<p>Add this as a script in your <code>package.json</code>:</p>
<pre><code class="language-json">{
  "scripts": {
    "inngest:dev": "npx inngest-cli@latest dev -u http://localhost:3000/api/inngest --no-discovery"
  }
}
</code></pre>
<p>Now you can trigger your functions by sending events from your API:</p>
<pre><code class="language-typescript">await inngest.send({
  name: "purchase/completed",
  data: {
    userId: "user_123",
    tier: "pro",
    sessionId: "cs_test_abc",
  },
});
</code></pre>
<p>The event appears in the Inngest dashboard, the function executes step by step, and you can see the output of each step. If a step fails, you can retry it manually from the dashboard.</p>
<h3 id="heading-how-to-handle-refunds-with-background-jobs">How to Handle Refunds with Background Jobs</h3>
<p>Here's a more complex example that shows why durable execution matters. When processing a refund, you need to update the purchase status, revoke access, send notifications, and track analytics. If any step fails, the others should still complete:</p>
<pre><code class="language-typescript">// src/lib/jobs/functions/stripe.ts
export const handleRefund = inngest.createFunction(
  {
    id: "refund-processed",
    triggers: [{ event: "stripe/charge.refunded" }],
  },
  async ({ event, step }) =&gt; {
    const { paymentIntentId, amountRefunded, originalAmount, currency } =
      event.data as {
        chargeId: string;
        paymentIntentId: string;
        amountRefunded: number;
        originalAmount: number;
        currency: string;
      };

    const isFullRefund = amountRefunded &gt;= originalAmount;

    // Step 1: Find the purchase and user
    const { user, purchase } = await step.run(
      "lookup-purchase",
      async () =&gt; {
        const purchaseResult = await db
          .select()
          .from(purchases)
          .where(eq(purchases.stripePaymentIntentId, paymentIntentId))
          .limit(1);

        if (!purchaseResult[0]) {
          return { user: null, purchase: null };
        }

        const userResult = await db
          .select()
          .from(users)
          .where(eq(users.id, purchaseResult[0].userId))
          .limit(1);

        return {
          user: userResult[0] ?? null,
          purchase: purchaseResult[0],
        };
      }
    );

    if (!purchase || !user) {
      return { success: false, reason: "no_matching_purchase" };
    }

    // Step 2: Update purchase status
    await step.run("update-purchase-status", async () =&gt; {
      await db
        .update(purchases)
        .set({
          status: isFullRefund ? "refunded" : "partially_refunded",
          updatedAt: new Date(),
        })
        .where(eq(purchases.id, purchase.id));
    });

    // Step 3: Send customer notification
    await step.run("notify-customer", async () =&gt; {
      console.log(
        `Sending \({isFullRefund ? "full" : "partial"} refund notification to \){user.email}`
      );
      // await sendEmail({ ... });
    });

    return { success: true, isFullRefund };
  }
);
</code></pre>
<p>Even if the email service is down in step 3, step 2 (updating the database) has already completed and will not be re-run. Inngest retries only the failed step.</p>
<p>This is what makes durable execution valuable for payment processing. You get reliable, idempotent processing without building your own retry logic.</p>
<h2 id="heading-how-to-deploy-to-vercel-with-neon">How to Deploy to Vercel with Neon</h2>
<p>You now have a working application with authentication, a database, a type-safe API, payments, and background jobs. Time to deploy it.</p>
<h3 id="heading-how-to-provision-a-neon-database">How to Provision a Neon Database</h3>
<ol>
<li><p>Sign up at <a href="https://neon.tech">neon.tech</a> and create a new project</p>
</li>
<li><p>Choose a region close to your users (Neon supports multiple AWS regions)</p>
</li>
<li><p>Copy the connection string from the dashboard</p>
</li>
</ol>
<p>The connection string looks like this:</p>
<pre><code class="language-text">postgresql://username:password@ep-something.us-east-1.aws.neon.tech/my_saas?sslmode=require
</code></pre>
<h3 id="heading-how-to-run-migrations-in-production">How to Run Migrations in Production</h3>
<p>For production, you should use versioned migrations instead of <code>db:push</code>. Generate a migration from your schema:</p>
<pre><code class="language-bash">bun run db:generate
</code></pre>
<p>This creates SQL files in the <code>drizzle/</code> directory. Review the generated SQL to make sure it matches your expectations. Then apply the migration:</p>
<pre><code class="language-bash">DATABASE_URL="your-neon-connection-string" bun run db:migrate
</code></pre>
<h3 id="heading-how-to-deploy-to-vercel">How to Deploy to Vercel</h3>
<ol>
<li><p>Push your code to a GitHub repository</p>
</li>
<li><p>Go to <a href="https://vercel.com/new">vercel.com/new</a> and import your repository</p>
</li>
<li><p>Vercel will auto-detect TanStack Start and configure the build settings</p>
</li>
</ol>
<p>Set the following environment variables in Vercel's dashboard:</p>
<table>
<thead>
<tr>
<th>Variable</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td><code>DATABASE_URL</code></td>
<td>Your Neon connection string</td>
</tr>
<tr>
<td><code>BETTER_AUTH_SECRET</code></td>
<td>Your random 32+ character string</td>
</tr>
<tr>
<td><code>BETTER_AUTH_URL</code></td>
<td><code>https://your-app.vercel.app</code></td>
</tr>
<tr>
<td><code>GITHUB_CLIENT_ID</code></td>
<td>Your GitHub OAuth client ID</td>
</tr>
<tr>
<td><code>GITHUB_CLIENT_SECRET</code></td>
<td>Your GitHub OAuth client secret</td>
</tr>
<tr>
<td><code>STRIPE_SECRET_KEY</code></td>
<td>Your Stripe secret key (live)</td>
</tr>
<tr>
<td><code>STRIPE_WEBHOOK_SECRET</code></td>
<td>Your Stripe webhook secret (production)</td>
</tr>
<tr>
<td><code>STRIPE_PRO_PRICE_ID</code></td>
<td>Your Stripe price ID</td>
</tr>
</tbody></table>
<p>Click "Deploy." Vercel builds your app and deploys it to a <code>.vercel.app</code> URL.</p>
<h3 id="heading-how-to-update-oauth-callbacks">How to Update OAuth Callbacks</h3>
<p>After deploying, update your GitHub OAuth app's callback URL:</p>
<ol>
<li><p>Go to your GitHub OAuth app settings</p>
</li>
<li><p>Change the <strong>Authorization callback URL</strong> to <code>https://your-app.vercel.app/api/auth/callback/github</code></p>
</li>
<li><p>Add <code>https://your-app.vercel.app</code> as the <strong>Homepage URL</strong></p>
</li>
</ol>
<h3 id="heading-how-to-configure-stripe-webhooks-for-production">How to Configure Stripe Webhooks for Production</h3>
<p>Create a webhook endpoint in the Stripe dashboard:</p>
<ol>
<li><p>Go to <a href="https://dashboard.stripe.com/webhooks">Stripe Dashboard &gt; Developers &gt; Webhooks</a></p>
</li>
<li><p>Click "Add endpoint"</p>
</li>
<li><p>Set the URL to <code>https://your-app.vercel.app/api/payments/webhook</code></p>
</li>
<li><p>Select the events you want to receive (<code>charge.refunded</code>, <code>checkout.session.expired</code>, and so on)</p>
</li>
<li><p>Copy the webhook signing secret and add it to Vercel's environment variables</p>
</li>
</ol>
<h3 id="heading-how-to-set-up-inngest-in-production">How to Set Up Inngest in Production</h3>
<p>Inngest has a cloud service that handles function execution in production:</p>
<ol>
<li><p>Sign up at <a href="https://www.inngest.com">inngest.com</a></p>
</li>
<li><p>Create an app and copy your event key and signing key</p>
</li>
<li><p>Add <code>INNGEST_EVENT_KEY</code> and <code>INNGEST_SIGNING_KEY</code> to Vercel's environment variables</p>
</li>
<li><p>In Inngest's dashboard, set your app URL to <code>https://your-app.vercel.app/api/inngest</code></p>
</li>
</ol>
<p>Inngest automatically discovers your functions and starts processing events.</p>
<h3 id="heading-common-deployment-pitfalls">Common Deployment Pitfalls</h3>
<p><strong>1. SSR externals.</strong> Some packages do not work with Vite's SSR bundling. If you see errors about packages like <code>elysia</code> or <code>inngest</code> during the build, add them to the <code>ssr.external</code> array in <code>vite.config.ts</code>:</p>
<pre><code class="language-typescript">// vite.config.ts
export default defineConfig({
  ssr: {
    external: ["elysia", "inngest"],
  },
  // ...
});
</code></pre>
<p><strong>2. Environment variable access.</strong> In TanStack Start, server-side code can access <code>process.env</code> directly. Client-side code can only access variables prefixed with <code>VITE_</code>. Your Stripe secret key and database URL should never have the <code>VITE_</code> prefix.</p>
<p><strong>3. Neon connection pooling.</strong> For production, use the pooled connection string from Neon (it uses port 5432 instead of the direct connection on port 5433). The pooled connection handles concurrent requests better.</p>
<p><strong>4. Build failures.</strong> If your build fails, the most common cause is a TypeScript error. Run <code>bun run type-check</code> locally before pushing. Fix all errors before deploying.</p>
<p><strong>5. Missing environment variables.</strong> If your app crashes immediately after deployment, check the Vercel function logs. The most common issue is a missing environment variable. Neon connection strings, Stripe keys, and Better Auth secrets all need to be set before the first deployment.</p>
<h3 id="heading-how-to-set-up-a-custom-domain">How to Set Up a Custom Domain</h3>
<p>Once your app is deployed to Vercel:</p>
<ol>
<li><p>Go to your project's Settings in Vercel</p>
</li>
<li><p>Click "Domains"</p>
</li>
<li><p>Add your custom domain</p>
</li>
<li><p>Update your DNS records as instructed (usually a CNAME record pointing to <code>cname.vercel-dns.com</code>)</p>
</li>
</ol>
<p>After adding a custom domain, update these environment variables in Vercel:</p>
<ul>
<li><p>Set <code>BETTER_AUTH_URL</code> to <code>https://yourdomain.com</code></p>
</li>
<li><p>Update your GitHub OAuth app's callback URL to <code>https://yourdomain.com/api/auth/callback/github</code></p>
</li>
<li><p>Update your Stripe webhook endpoint to <code>https://yourdomain.com/api/payments/webhook</code></p>
</li>
</ul>
<p>Vercel automatically provisions an SSL certificate for your custom domain. No additional configuration needed.</p>
<h3 id="heading-how-to-verify-your-deployment">How to Verify Your Deployment</h3>
<p>After deploying, run through this checklist:</p>
<ol>
<li><p><strong>Health check.</strong> Visit <code>https://yourdomain.com/api/health</code>. You should see a JSON response with <code>{ "status": "ok" }</code>.</p>
</li>
<li><p><strong>Authentication.</strong> Click "Sign in with GitHub" and complete the OAuth flow. You should be redirected to your dashboard.</p>
</li>
<li><p><strong>Database.</strong> After signing in, check your Neon dashboard. You should see a new row in the <code>users</code> table.</p>
</li>
<li><p><strong>Payments.</strong> On your pricing page, click "Buy" and use Stripe's test card (<code>4242 4242 4242 4242</code>) to complete a purchase. Check that a purchase record appears in your database.</p>
</li>
<li><p><strong>Background jobs.</strong> After a test purchase, check the Inngest dashboard. You should see a <code>purchase/completed</code> event and the corresponding function execution.</p>
</li>
</ol>
<p>If any of these steps fail, check the Vercel function logs (Settings, Functions, Logs) for error messages. Most deployment issues are misconfigured environment variables or missing webhook secrets.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You just built a production-ready SaaS application. Let's recap what you have:</p>
<ul>
<li><p><strong>TanStack Start</strong> handles server-side rendering, file-based routing, and the dev server</p>
</li>
<li><p><strong>Elysia</strong> provides a type-safe API embedded in the same process as your web app</p>
</li>
<li><p><strong>Eden Treaty</strong> gives you a fully typed API client with zero code generation</p>
</li>
<li><p><strong>Drizzle ORM with Neon</strong> handles your database with type-safe queries and serverless PostgreSQL</p>
</li>
<li><p><strong>Better Auth</strong> provides GitHub OAuth with session management and route protection</p>
</li>
<li><p><strong>Stripe</strong> processes payments with webhook handling</p>
</li>
<li><p><strong>Inngest</strong> runs reliable background jobs with automatic retries and checkpointing</p>
</li>
<li><p><strong>Vercel</strong> hosts everything with zero infrastructure management</p>
</li>
</ul>
<p>The four-layer pattern (Schema, API, Hooks, UI) gives you a repeatable process for adding new features. Every feature follows the same structure. Define the data, expose it through the API, connect it to React with hooks, and render it in your components.</p>
<p>This architecture scales well. The explicit boundaries between layers mean you can swap out individual pieces without rewriting everything.</p>
<p>If you outgrow Neon, switch to a self-hosted PostgreSQL. If you need a different payment provider, replace the Stripe module. The rest of the application doesn't change.</p>
<p>What you build next is up to you. Here are natural next steps:</p>
<ul>
<li><p><strong>Email notifications</strong> with <a href="https://resend.com">Resend</a> and <a href="https://react.email">React Email</a> for transactional emails (purchase confirmations, password resets, welcome sequences)</p>
</li>
<li><p><strong>Analytics</strong> with <a href="https://posthog.com">PostHog</a> for tracking user behavior and feature flags</p>
</li>
<li><p><strong>Error tracking</strong> with <a href="https://sentry.io">Sentry</a> for catching production errors before your users report them</p>
</li>
<li><p><strong>Content management</strong> with MDX for a blog or documentation section</p>
</li>
<li><p><strong>File uploads</strong> with S3-compatible storage for user-generated content</p>
</li>
</ul>
<p>The <code>src/lib/</code> pattern makes adding new integrations straightforward. Create a new directory, add an <code>index.ts</code>, and import it where you need it. Each integration stays isolated, so adding analytics does not affect your payment code.</p>
<p>If you want to skip the setup and start building your product immediately, <a href="https://eden-stack.com?utm_source=freecodecamp&amp;utm_medium=article&amp;utm_campaign=fullstack-saas-handbook">Eden Stack</a> includes everything from this article (and more), pre-configured and production-tested. It ships with 30+ Claude Code skills that encode the patterns described here, so AI coding assistants can generate features following your codebase conventions out of the box.</p>
<p>Whatever you build, build it with type safety. The feedback loop of "change the schema, see the errors, fix the errors" is the fastest way I know to ship reliable software.</p>
<p><em>Magnus Rodseth builds AI-native applications and is the creator of</em> <a href="https://eden-stack.com?utm_source=freecodecamp&amp;utm_medium=article&amp;utm_campaign=fullstack-saas-handbook"><em>Eden Stack</em></a><em>, a production-ready starter kit with 30+ Claude skills encoding production patterns for AI-native SaaS development.</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Design a Type-Safe, Lazy, and Secure Plugin Architecture in React ]]>
                </title>
                <description>
                    <![CDATA[ Modern web applications increasingly need to evolve faster than a single team can maintain a monolithic codebase. Product teams often want to add features independently, experiment with new capabiliti ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-design-a-type-safe-lazy-and-secure-plugin-architecture-in-react/</link>
                <guid isPermaLink="false">69caa5bc9fffa747404dbd51</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ plugin ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Frontend Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jessica Patel ]]>
                </dc:creator>
                <pubDate>Mon, 30 Mar 2026 15:00:00 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/5cdc3448-3bf8-456e-b316-33c6bcb98690.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Modern web applications increasingly need to evolve faster than a single team can maintain a monolithic codebase. Product teams often want to add features independently, experiment with new capabilities, or deploy domain-specific functionality without modifying the core application every time. This is where a plugin architecture becomes valuable.</p>
<p>A plugin architecture allows an application to load external modules that extend its functionality at runtime. Instead of embedding every feature directly in the core application, the system exposes a controlled interface (the host API) that plugins use to integrate with the platform. These plugins can register UI components, contribute functionality, or interact with application services while remaining isolated from the core codebase.</p>
<p>This architectural pattern is widely used across software ecosystems. Platforms such as IDEs, content management systems, and browser extensions rely on plugins to allow third-party developers to extend their functionality without compromising stability.</p>
<p>In a web application context, a similar approach allows large frontend systems to evolve modularly, enabling multiple teams to ship features independently.</p>
<p>In this tutorial, you'll learn how to design a type-safe, lazy-loaded, and secure plugin architecture in React — complete with lifecycle management, independent bundling, hot-loading, and real TypeScript examples.</p>
<p>By the end, you'll have everything you need to transform your React application into a modular platform capable of hosting independent extensions without sacrificing maintainability, performance, or security.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-a-common-pain-point-scaling-frontend-platforms">A Common Pain Point: Scaling Frontend Platforms</a></p>
</li>
<li><p><a href="#heading-what-this-article-will-cover">What This Article Will Cover</a></p>
</li>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-why-a-plugin-architecture">Why a Plugin Architecture?</a></p>
</li>
<li><p><a href="#heading-core-concepts-of-a-react-plugin-architecture">Core Concepts of a React Plugin Architecture</a></p>
</li>
<li><p><a href="#heading-high-level-architecture-of-a-react-plugin-system">High-Level Architecture of a React Plugin System</a></p>
</li>
<li><p><a href="#heading-real-typescript-example-a-chat-plugin">Real TypeScript Example: A Chat Plugin</a></p>
<ul>
<li><p><a href="#heading-chat-plugin-implementation">Chat Plugin Implementation</a></p>
</li>
<li><p><a href="#heading-host-application-usage">Host Application Usage</a></p>
</li>
<li><p><a href="#heading-1-how-to-define-the-host-api">1. How to Define the Host API</a></p>
</li>
<li><p><a href="#heading-2-how-to-define-the-plugin-lifecycle">2. How to Define the Plugin Lifecycle</a></p>
</li>
<li><p><a href="#heading-3-how-to-bundle-plugins-separately">3. How to Bundle Plugins Separately</a></p>
</li>
<li><p><a href="#heading-4-how-to-lazy-load-plugins">4. How to Lazy-Load Plugins</a></p>
</li>
<li><p><a href="#heading-5-security-permission-model">5. Security &amp; Permission Model</a></p>
</li>
<li><p><a href="#heading-6-plugin-hot-loading">6. Plugin Hot-loading</a></p>
</li>
<li><p><a href="#heading-7-ci-deployment-considerations">7. CI &amp; Deployment Considerations</a></p>
</li>
<li><p><a href="#heading-putting-it-all-together">Putting It All Together</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-best-practices">Best Practices</a></p>
</li>
<li><p><a href="#heading-when-not-to-use-a-plugin-architecture">When NOT to Use a Plugin Architecture</a></p>
<ul>
<li><p><a href="#heading-small-or-single-team-applications">Small or Single-Team Applications</a></p>
</li>
<li><p><a href="#heading-tightly-coupled-features">Tightly Coupled Features</a></p>
</li>
<li><p><a href="#heading-performance-critical-systems">Performance-Critical Systems</a></p>
</li>
<li><p><a href="#heading-limited-security-controls">Limited Security Controls</a></p>
</li>
<li><p><a href="#heading-early-stage-products">Early-Stage Products</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-future-enhancements">Future Enhancements</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-a-common-pain-point-scaling-frontend-platforms">A Common Pain Point: Scaling Frontend Platforms</h2>
<p>Consider a large internal admin dashboard used by multiple teams across an organization. Each team wants to add its own functionality, like analytics dashboards, workflow management tools, user administration panels, and domain-specific reporting modules.</p>
<p>If all these features are implemented directly in the main React application, several problems quickly emerge. Merge conflicts in the core repository become frequent, unrelated features grow tightly coupled, and release cycles slow down because every change requires redeploying the entire application. Worse, adding new features carries a constant risk of breaking existing functionality.</p>
<p>A plugin architecture solves this problem by allowing each feature to be developed as an independent plugin. The host application provides a stable platform and a controlled API, while teams can ship their own plugins without modifying the core system.</p>
<h2 id="heading-what-this-article-will-cover">What This Article Will Cover</h2>
<p>This guide walks you through how to design a type-safe, lazy-loaded, and secure plugin architecture in React using TypeScript. You'll learn how to design a host API that plugins can safely interact with, how to define a plugin lifecycle for initialization, mounting, updates, and cleanup, and how to bundle plugins independently so they can be developed and deployed separately.</p>
<p>You'll also learn how to lazy-load plugins at runtime to improve performance, how to implement a security model that prevents plugins from accessing sensitive application state, and how to enable hot-loading during development while enforcing safety through CI/CD pipelines.</p>
<p>By the end of this article, you'll understand how to build a flexible plugin system that allows your React application to grow into a modular platform capable of hosting independent extensions without sacrificing maintainability, performance, or security.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before following along with this guide, you should be familiar with several core technologies and concepts used throughout the examples.</p>
<p><strong>React Fundamentals</strong><br>A basic understanding of React components, hooks, and JSX is required. The examples assume familiarity with functional components, <code>useState</code>, and <code>useEffect</code>.</p>
<p><strong>TypeScript Basics</strong><br>Since the plugin architecture relies heavily on type contracts between the host application and plugins, you should understand TypeScript interfaces, generics, and module exports.</p>
<p><strong>Modern JavaScript Modules</strong><br>Knowledge of ES modules (<code>import</code> / <code>export</code>) and dynamic imports will help when working with lazy-loaded plugins.</p>
<p><strong>React Tooling (Vite or Webpack)</strong><br>The examples reference modern frontend build tools such as Vite. Familiarity with how bundlers compile React applications and manage dependencies will help when configuring plugin builds.</p>
<p><strong>Basic Web Security Concepts</strong><br>Some sections discuss sandboxing and restricted APIs. A general understanding of browser security concepts such as iframes, same-origin policies, and API boundaries is helpful but not strictly required.</p>
<h2 id="heading-why-a-plugin-architecture">Why a Plugin Architecture?</h2>
<p>Imagine you're building an internal admin platform where multiple teams need to ship independent features as plugins without risking the core application. A plugin architecture allows each team to contribute functionality safely, while the host maintains type safety, security, and performance.</p>
<p>This guide targets React/TypeScript engineers who want to design a plugin system capable of hosting third-party extensions without compromising maintainability.</p>
<p>The benefits of this approach are significant. Extensibility means developers or third parties can add features without touching core code. Isolation allows plugins to be sandboxed so they can't affect unrelated parts of the application. Lazy loading ensures only the features a user actually needs are fetched, keeping the application fast. TypeScript enforces a strict contract between plugins and the host, catching errors at compile time rather than at runtime. Finally, controlled APIs and permission boundaries prevent malicious or poorly written plugins from interfering with the rest of the system.</p>
<p>A well-architected plugin system balances all of these qualities – flexibility, safety, and maintainability – without forcing unnecessary trade-offs between them.</p>
<h2 id="heading-core-concepts-of-a-react-plugin-architecture">Core Concepts of a React Plugin Architecture</h2>
<p>Before diving into code, it helps to understand the key building blocks that make up a React plugin system.</p>
<p>At a high level, a plugin architecture in React revolves around five concerns.</p>
<ol>
<li><p>The <strong>Host API</strong> is the interface the core application exposes to plugins.</p>
</li>
<li><p>The <strong>Plugin Lifecycle</strong> defines methods for initialization, mounting, updating, and cleanup.</p>
</li>
<li><p><strong>Bundling</strong> means compiling each plugin separately to avoid coupling it to the host.</p>
</li>
<li><p>The <strong>Security Model</strong> covers permissions and sandboxing to prevent misuse.</p>
</li>
<li><p>Finally, <strong>Hot-loading and CI</strong> streamline the development and deployment experience.</p>
</li>
</ol>
<p>We'll explore each of these concepts in detail in the sections that follow. First, let's look at how they fit together visually.</p>
<h2 id="heading-high-level-architecture-of-a-react-plugin-system">High-Level Architecture of a React Plugin System</h2>
<p>The following diagram illustrates how the host application interacts with independently bundled plugins. The host exposes a controlled API, loads plugins dynamically, and manages their lifecycle while maintaining security boundaries.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6979762ba2442d262dacf388/5b7ef89a-62ae-4ea0-97f5-34a2423650d3.png" alt="React Plugin Architecture" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>The core application serves as the runtime environment for all plugins, housing the plugin loader, lifecycle manager, and the host API.</p>
<p>The plugin loader dynamically imports plugin bundles at runtime using <code>import()</code>, while the host API ensures plugins interact with the application through a controlled interface rather than accessing internal state directly.</p>
<p>Each plugin is compiled as a separate bundle and registers itself with the host during initialization. A dedicated security layer enforces all of these boundaries, ensuring plugins cannot directly manipulate internal state or sensitive resources.</p>
<p>Together, these pieces ensure that plugins remain independent, lazy-loadable, and secure, while the host application retains full control over lifecycle management and platform stability.</p>
<h2 id="heading-real-typescript-example-a-chat-plugin">Real TypeScript Example: A Chat Plugin</h2>
<p>Now that you have a mental model of the architecture, let's look at a minimal working example before diving into each concept individually. This example demonstrates how a plugin registers itself with the host application and exposes a UI component through the host API.</p>
<p>The following plugin implements a simple chat feature that registers a React component with the host platform.</p>
<h3 id="heading-chat-plugin-implementation">Chat Plugin Implementation</h3>
<pre><code class="language-typescript">// plugins/chat-plugin/src/plugin.ts

import { Plugin, HostAPI } from '../../src/plugins';

const ChatPlugin: Plugin = {
  name: 'ChatPlugin',
  version: '1.0.0',
  init(host: HostAPI) {
    host.registerComponent('Chat', () =&gt; (
      &lt;div&gt;Welcome to the Chat Plugin!&lt;/div&gt;
    ));
    host.log('ChatPlugin initialized');
  },
};

export default ChatPlugin;
</code></pre>
<h3 id="heading-host-application-usage">Host Application Usage</h3>
<p>The host application loads the plugin and renders the component it registered.</p>
<pre><code class="language-typescript">const Chat = hostAPI.getComponent('Chat');

return (
  &lt;div&gt;
    {Chat ? &lt;Chat /&gt; : 'Loading Chat Plugin...'}
  &lt;/div&gt;
);
</code></pre>
<p>In this example, the plugin doesn't directly modify the host application. Instead, it interacts through the Host API, registering a component that the host can render dynamically. The sections below break down exactly how each piece of this system is built.</p>
<h3 id="heading-1-how-to-define-the-host-api">1. How to Define the Host API</h3>
<p>The <strong>host API</strong> is the contract between the core app and its plugins. It defines what functionality plugins can access. Before plugins can do anything useful, the host must expose a controlled interface, establishing the contract between the core application and its extensions.</p>
<p><strong>Example: TypeScript Host API</strong></p>
<pre><code class="language-typescript">// src/plugins/host.ts

export interface HostAPI {
  // Using ComponentType instead of FC&lt;any&gt; reinforces type-safety while allowing class/function components
  registerComponent: (name: string, component: React.ComponentType&lt;any&gt;) =&gt; void;
  getComponent: (name: string) =&gt; React.ComponentType&lt;any&gt; | undefined;
  log: (message: string) =&gt; void;
}

// Note: We still use `any` for props here for extensibility; plugins can define stricter props locally if needed.

export const hostAPI: HostAPI = { 
    registerComponent(name, component) { 
        console.log(Registered component: ${name}); 
        componentRegistry[name] = component; 
    }, 
    getComponent(name) { 
        return componentRegistry[name]; 
    }, 
    log(message) { 
        console.log([PLUGIN LOG]: ${message}); 
    }, 
};

const componentRegistry: Record&lt;string, React.ComponentType&lt;any&gt;&gt; = {};
</code></pre>
<p>This API allows plugins to register UI components and log messages, without giving them unrestricted access to the application state.</p>
<h3 id="heading-2-how-to-define-the-plugin-lifecycle">2. How to Define the Plugin Lifecycle</h3>
<p>A plugin lifecycle ensures consistent behavior across all extensions. Once the host API exists, plugins need a structured way to initialize, render, and clean up resources.</p>
<p><strong>Lifecycle Interface</strong></p>
<pre><code class="language-typescript">// src/plugins/plugin.ts

import { HostAPI } from './host';

export interface Plugin {
  name: string;
  version: string;
  init: (host: HostAPI) =&gt; void;
  mount?: () =&gt; void;
  update?: () =&gt; void;
  unmount?: () =&gt; void;
}

// Typically, the host calls mount/update/unmount based on route changes, feature flags, or user interactions.
</code></pre>
<p>The <code>init</code> method is called when the plugin is first loaded and receives the host API as its argument. <code>mount</code> is called when the plugin's UI is displayed, while <code>update</code> is an optional hook triggered when props or state change.</p>
<p>When a plugin is removed, <code>unmount</code> is called to clean up any resources the plugin was holding, preventing memory leaks and side effects in the host application.</p>
<h3 id="heading-3-how-to-bundle-plugins-separately">3. How to Bundle Plugins Separately</h3>
<p>Each plugin should be packaged as an independent module so that it can be developed, versioned, and deployed without tightly coupling it to the host application.</p>
<p>Modern build tools such as Vite or Webpack make it possible to compile plugins into standalone bundles that the host can load dynamically at runtime.</p>
<p><strong>Example Vite Configuration for a Plugin</strong></p>
<pre><code class="language-typescript">// vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    lib: {
      entry: 'src/plugin.ts',
      name: 'MyPlugin',
      fileName: 'my-plugin',
      formats: ['es'],
    },
    rollupOptions: {
      external: ['react', 'react-dom'],
    },
  },
});
</code></pre>
<p>The <code>external</code> option ensures the plugin uses the host's React, preventing duplicate React versions in memory.</p>
<h3 id="heading-4-how-to-lazy-load-plugins">4. How to Lazy-Load Plugins</h3>
<p>Even when plugins are bundled independently, loading all of them during application startup would significantly increase initial load time. Instead, plugins should be loaded on demand using dynamic imports so that functionality is only fetched when the user actually needs it.</p>
<pre><code class="language-typescript">// src/plugins/loader.ts

export async function loadPlugin(url: string): Promise { 

    // Using /* @vite-ignore */ because the URL is dynamic and cannot be         statically analyzed by Vite.
    // Tradeoff: plugin cannot be pre-bundled; ensure URLs are trusted to avoid security risks.

    const module = await import(/ @vite-ignore */ url); 
    return module.default as Plugin; 
}
</code></pre>
<p><strong>Usage in React:</strong></p>
<pre><code class="language-typescript">const [plugin, setPlugin] = React.useState&lt;Plugin | null&gt;(null);

React.useEffect(() =&gt; {
  loadPlugin('/plugins/my-plugin.js').then((p) =&gt; {
    p.init(hostAPI);
    setPlugin(p);
  });
}, []);
</code></pre>
<p>This pattern allows applications to scale without preloading all plugins, improving initial load time.</p>
<h3 id="heading-5-security-amp-permission-model">5. Security &amp; Permission Model</h3>
<p>Because plugins run code that originates outside the core application, security boundaries are essential. Even though plugins interact through the host API, the platform must still restrict what capabilities they can access in order to prevent misuse or accidental interference with application state.</p>
<p><strong>Example: Restricted API</strong></p>
<pre><code class="language-typescript">export interface SecureHostAPI {
  log: (message: string) =&gt; void;
  registerComponent: (name: string, component: React.ComponentType&lt;any&gt;) =&gt; void;
  fetchData?: (endpoint: string) =&gt; Promise&lt;any&gt;; // Only if allowed
}
</code></pre>
<p>You can enhance security further using <strong>iframe sandboxing</strong> or <strong>Web Workers</strong> for heavier isolation.</p>
<pre><code class="language-typescript">// Example of a sandboxed iframe plugin

&lt;iframe
  src="/plugins/my-plugin.html"
  sandbox="allow-scripts"
  style={{ width: '100%', height: '400px', border: 'none' }}
/&gt;

// Advanced isolation notes:
// - You can define different SecureHostAPI shapes for internal vs. third-party plugins,
//   exposing more capabilities to trusted plugins while restricting untrusted ones.
// - For stronger isolation, use message passing (postMessage) with iframes or Web Workers
//   so plugins cannot access the DOM or host state directly.
</code></pre>
<p>This approach prevents DOM and network access outside the API.</p>
<h3 id="heading-6-plugin-hot-loading">6. Plugin Hot-loading</h3>
<p>Hot-loading is essential for developer productivity. Tools like Vite's HMR let you see plugin updates immediately, speeding up iteration and reducing friction.</p>
<p><strong>React Example with HMR:</strong></p>
<pre><code class="language-typescript">if (import.meta.hot) {
  import.meta.hot.accept('/plugins/my-plugin.js', (newModule) =&gt; {
    const updatedPlugin = newModule.default as Plugin;
    updatedPlugin.init(hostAPI);
    setPlugin(updatedPlugin);
  });
}
</code></pre>
<p>With hot-loading, developers can update plugins without restarting the host app.</p>
<h3 id="heading-7-ci-amp-deployment-considerations">7. CI &amp; Deployment Considerations</h3>
<p>To deploy safely, plugins must be verified and tested. CI/CD pipelines enforce type safety, bundling, and security checks automatically. For a production-grade plugin system, continuous integration pipelines should:</p>
<ol>
<li><p>Lint and type-check each plugin using TypeScript.</p>
</li>
<li><p>Run automated tests to ensure plugin compliance.</p>
</li>
<li><p>Bundle plugins independently with versioned outputs.</p>
</li>
<li><p>Deploy plugins to a secure CDN or internal repository.</p>
</li>
<li><p>Verify signatures or hashes to prevent tampering.</p>
</li>
</ol>
<p><strong>GitHub Actions Example for Plugin CI:</strong></p>
<pre><code class="language-plaintext">name: Build Plugin

on:
  push:
    paths:
      - 'plugins/**'

jobs:
  build:
    runs-on: ubuntu-latest
    steps: 
      - uses: actions/checkout@v3 
      - uses: actions/setup-node@v3 
      with:
        node-version: 20
      - run: npm install 
      - run: npm run build --workspace plugins/my-plugin 
      - run: npm run test --workspace plugins/my-plugin
      # Optional: sign plugin artifacts or generate a checksum to verify integrity before loading in the host
</code></pre>
<p>This ensures every plugin is type-safe, tested, and ready for deployment.</p>
<h3 id="heading-putting-it-all-together">Putting It All Together</h3>
<p>At this point, you have walked through each architectural layer independently. Here's how all the pieces map to a real project structure:</p>
<pre><code class="language-plaintext">src/
├── plugins/ 
│ ├── host.ts ← Host API definition 
│ ├── plugin.ts ← Plugin lifecycle interface 
│ └── loader.ts ← Dynamic plugin loader 
plugins/ 
└── chat-plugin/ 
    └── src/ 
        └── plugin.ts ← Chat plugin implementation
</code></pre>
<p>Each file has a single, clear responsibility. <code>host.ts</code> owns the contract, <code>plugin.ts</code> owns the lifecycle shape, <code>loader.ts</code> handles runtime importing, and the plugin itself lives entirely outside the core <code>src/</code> tree – deployable and versioned independently.</p>
<h2 id="heading-best-practices">Best Practices</h2>
<p>At this point, you have a host API, a well-defined plugin lifecycle, isolated bundles, lazy-loading, and a security model. These foundations ensure plugins are robust, type-safe, and maintainable — ready to be extended with versioning, testing, and CI/CD pipelines.</p>
<ol>
<li><p><strong>Type safety:</strong> Always define TypeScript interfaces for host APIs and plugin contracts.</p>
</li>
<li><p><strong>Lazy loading:</strong> Only load plugins when required.</p>
</li>
<li><p><strong>Security:</strong> Expose a minimal API and avoid giving plugins unrestricted access.</p>
</li>
<li><p><strong>Isolated state:</strong> Keep plugin state isolated to prevent accidental interference.</p>
</li>
<li><p><strong>Versioning:</strong> Maintain plugin versions to ensure compatibility with the host.</p>
</li>
<li><p><strong>Testing:</strong> Unit-test plugins against host API mocks.</p>
</li>
<li><p><strong>CI/CD:</strong> Automate linting, testing, and bundling for plugins.</p>
</li>
</ol>
<h2 id="heading-when-not-to-use-a-plugin-architecture">When NOT to Use a Plugin Architecture</h2>
<p>In some cases, introducing a plugin system can add unnecessary complexity without delivering meaningful benefits.</p>
<h3 id="heading-small-or-single-team-applications">Small or Single-Team Applications</h3>
<p>If a project is maintained by a small team and the feature set is relatively stable, a plugin architecture may be excessive. A simpler modular structure within the main codebase is usually easier to maintain and reason about.</p>
<h3 id="heading-tightly-coupled-features">Tightly Coupled Features</h3>
<p>Plugin systems work best when features can operate independently. If new functionality requires deep access to application state or tightly integrated workflows, forcing it into a plugin model may introduce unnecessary abstractions and complexity rather than solving a real problem.</p>
<h3 id="heading-performance-critical-systems">Performance-Critical Systems</h3>
<p>Although lazy-loading can mitigate performance issues, plugin architectures still introduce additional runtime complexity. Applications with strict performance constraints may benefit from a more tightly optimized architecture rather than dynamic plugin loading.</p>
<h3 id="heading-limited-security-controls">Limited Security Controls</h3>
<p>Allowing external code to run inside an application always introduces security risks. If the platform can't enforce strong API boundaries, sandboxing, or validation of plugins, it may be safer to avoid a plugin architecture altogether.</p>
<h3 id="heading-early-stage-products">Early-Stage Products</h3>
<p>In early product development, requirements often change rapidly. Designing a plugin system too early can slow development because engineers must maintain abstraction layers before the product's core architecture has stabilized. It's usually better to wait until the platform's boundaries are well understood before introducing this level of extensibility.</p>
<h2 id="heading-future-enhancements">Future Enhancements</h2>
<p>As the platform matures, there are several directions worth exploring.</p>
<p>Dynamic permissions would allow plugins to explicitly request capabilities, with the host deciding whether to grant them. This makes the security model more granular and auditable.</p>
<p>A plugin marketplace could serve as a central registry of verified plugins, making discovery and distribution easier for teams.</p>
<p>For use cases that require stronger isolation, Web Workers or iframes offer more robust sandboxing than API boundaries alone.</p>
<p>An event bus is another useful addition, allowing plugins to communicate with each other through a shared message system rather than direct API calls, which keeps inter-plugin dependencies loose and manageable.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Designing a plugin architecture in React is ultimately about treating your application as a platform rather than a single codebase. By defining clear contracts between the host application and its extensions, you enable teams to ship features independently while preserving stability, security, and performance.</p>
<p>If you are building a system that multiple teams (or even third-party developers) need to extend, start by establishing a minimal host API and plugin contract. Focus on strong TypeScript interfaces, clear lifecycle boundaries, and strict API access rules. These foundations ensure that plugins remain predictable and safe as the ecosystem grows.</p>
<p>As your platform evolves, you can gradually introduce more advanced capabilities such as plugin versioning, capability-based permissions, sandboxed execution environments, or an internal plugin marketplace.</p>
<p>Observability and monitoring also become increasingly important as the number of plugins grows, allowing you to detect compatibility issues or performance regressions early.</p>
<p>The key takeaway is to start simple but intentional. A small, well-defined plugin interface combined with lazy loading and secure API boundaries is often enough to support the first generation of extensions. From there, your architecture can expand naturally into a full ecosystem where features are delivered as modular, independently deployable plugins.</p>
<p>When implemented thoughtfully, a React plugin architecture transforms a single application into a scalable, extensible platform capable of supporting long-term growth and collaboration across teams.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Common React Mistakes to Avoid ]]>
                </title>
                <description>
                    <![CDATA[ By Scott Gary React is a highly popular and powerful JavaScript library for user interface development. Its component-based architecture, combined with its declarative nature, is one of the primary reasons it works well for both small and large-scale... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/react-common-mistakes/</link>
                <guid isPermaLink="false">66d460f651f567b42d9f84ab</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 06 Aug 2024 22:19:05 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/08/react-mistakes.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Scott Gary</p>
<p>React is a highly popular and powerful JavaScript library for user interface development. Its component-based architecture, combined with its declarative nature, is one of the primary reasons it works well for both small and large-scale applications. </p>
<p>But like with any technology, there are pitfalls that you can fall into when you're writing React code if you're not careful. </p>
<p>In this article, we will discuss these common mistakes and I'll provide you with best practices to avoid them. This will help you keep your React projects efficient, maintainable, and scalable.</p>
<h2 id="heading-1-mistakes-in-key-props-usage">1. Mistakes in Key Props Usage</h2>
<p>One of the most common mistakes when using React involves the key prop. There are several scenarios where key props are used, with lists being the most common. </p>
<p>The key prop is crucial because it helps React track which items have changed, been added, or removed. If they are not correctly set, React's diffing algorithm can become inefficient, leading to performance issues and bugs.</p>
<p><strong>Best Practice:</strong> Always pass a stable and unique key for the items in a list. If possible, use unique IDs from your data instead of array indices as keys.</p>
<pre><code><span class="hljs-keyword">const</span> ItemList = <span class="hljs-function">(<span class="hljs-params">{ items }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
    {items.map(item =&gt; (
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>{item.name}<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><p>In the above code snippet, each item in the list has a key with <code>item.id</code>. This ensures that every list item is uniquely identifiable, helping React render more efficiently and reduce unnecessary renders.  </p>
<p>For more tips on optimizing performance, check out this article on <a target="_blank" href="https://www.freecodecamp.org/news/caching-in-react/">caching in React</a>.</p>
<h2 id="heading-2-ignoring-the-virtual-dom">2. Ignoring the Virtual DOM</h2>
<p>Some developers mistakenly believe that the role of the Virtual DOM means they need to update the DOM themselves. This goes against how React works and can result in unpredictability and bugs.</p>
<h3 id="heading-what-is-the-virtual-dom">What is the Virtual DOM?</h3>
<p>For those new to React, the Virtual DOM is an in-memory representation of the real DOM. It allows React to update the UI efficiently by minimizing direct manipulations of the actual DOM. React compares the new Virtual DOM with the previous one and updates only the necessary parts of the real DOM. </p>
<p>Developers might assume they need to synchronize the Virtual DOM with the real DOM due to experiences with other libraries or frameworks.</p>
<p><strong>Best Practice:</strong> Always let React handle the DOM. If you must interact directly with the DOM, use refs.</p>
<pre><code><span class="hljs-keyword">const</span> ItemList = <span class="hljs-function">(<span class="hljs-params">{ items }</span>) =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
    {items.map(item =&gt; (
      <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{item.id}</span>&gt;</span>{item.name}<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><p><strong>Explanation:</strong></p>
<p>Using a unique identifier from the data, such as <code>item.id</code>, ensures that each key is unique and stable. This allows React to efficiently determine which items have changed, been added, or removed. It helps React's reconciliation algorithm to update the UI efficiently and prevents bugs related to item reordering or deletion.</p>
<h2 id="heading-3-overusing-state">3. Overusing State</h2>
<p>State management is crucial in React, but excessive state usage can make a component complex and difficult to maintain. Any change in state triggers a re-render, which can be expensive if not handled properly.</p>
<p><strong>Best Practice:</strong> Minimize the use of state and lift state only when necessary. For global state, use contexts or state management libraries like Redux.</p>
<pre><code><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">const</span> MyComponent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);
  <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>); <span class="hljs-comment">// Additional state</span>

  <span class="hljs-keyword">const</span> handleIncrement = <span class="hljs-function">() =&gt;</span> setCount(count + <span class="hljs-number">1</span>);
  <span class="hljs-keyword">const</span> handleNameChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setName(e.target.value);

  <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>Count: {count}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleIncrement}</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">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">{name}</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleNameChange}</span>
        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter name"</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};
</code></pre><p>In the above example, the <code>useState</code> hook is used to maintain a simple count state. When the button is pressed, it displays and increments the count, demonstrating a very basic use of state.</p>
<h2 id="heading-4-forgetting-to-clean-up-effects">4. Forgetting to Clean Up Effects</h2>
<p>When using the useEffect hook, it is essential to clean up side effects to prevent memory leaks and other unintended behaviors. Side effects might include setting up subscriptions, timers, or event listeners that need to be cleared when the component unmounts or when the effect dependencies change.</p>
<p><strong>Best Practice:</strong> Always return a cleanup function from your effect when setting up side effects that need to be cleared.  </p>
<p>Example without Cleanup:</p>
<pre><code><span class="hljs-keyword">const</span> Timer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [time, setTime] = React.useState(<span class="hljs-number">0</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> intervalId = <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
      setTime(<span class="hljs-function"><span class="hljs-params">prevTime</span> =&gt;</span> prevTime + <span class="hljs-number">1</span>);
    }, <span class="hljs-number">1000</span>);
    <span class="hljs-comment">// No cleanup function provided here</span>
  }, []);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Time: {time}s<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};
</code></pre><p>In the example above, a timer is set up with <code>setInterval</code>, but no cleanup function is provided to clear the interval when the component unmounts. This can lead to memory leaks.</p>
<p><strong>Correct</strong>: Cleanup with <code>useEffect</code>:</p>
<pre><code><span class="hljs-keyword">const</span> Timer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [time, setTime] = React.useState(<span class="hljs-number">0</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> intervalId = <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
      setTime(<span class="hljs-function"><span class="hljs-params">prevTime</span> =&gt;</span> prevTime + <span class="hljs-number">1</span>);
    }, <span class="hljs-number">1000</span>);

    <span class="hljs-comment">// Cleanup function to clear the interval</span>
    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearInterval</span>(intervalId);
  }, []);

  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Time: {time}s<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};
</code></pre><p>In this corrected example, a cleanup function is provided to clear the interval when the component unmounts, preventing potential memory leaks.</p>
<h2 id="heading-5-ignoring-performance">5. Ignoring Performance</h2>
<p>A React application can encounter serious performance issues, such as excessive re-renders and heavy calculations during render.</p>
<p><strong>Best Practice:</strong> Memoize components and values using <code>React.memo</code>, <code>useMemo</code>, and <code>useCallback</code> for improved performance.</p>
<pre><code><span class="hljs-keyword">const</span> MemoizedComponent = React.memo(<span class="hljs-function">(<span class="hljs-params">{ data }</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>{data}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
});
</code></pre><p>This example uses <code>React.memo</code> to memoize a functional component, preventing it from re-rendering unnecessarily when the <code>data</code> prop hasn't changed.</p>
<h2 id="heading-6-overusing-the-context-api">6. Overusing the Context API</h2>
<p>The Context API is very handy for passing data through your component tree without prop drilling. But it's often overused, leading to performance issues.</p>
<p><strong>Best Practice:</strong> Avoid using context for frequently changing values. Mainly use it for static values or rare updates.</p>
<pre><code><span class="hljs-keyword">const</span> ThemeContext = React.createContext(<span class="hljs-string">'light'</span>);

<span class="hljs-keyword">const</span> ThemedComponent = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> theme = useContext(ThemeContext);
  <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">{theme}</span>&gt;</span>Themed Component<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};
</code></pre><p>In the above example, <code>ThemeContext</code> is initialized with the default value <code>'light'</code>. The <code>ThemedComponent</code> uses the <code>useContext</code> hook to get the actual value of the theme.</p>
<h2 id="heading-7-not-handling-errors-properly">7. Not Handling Errors Properly</h2>
<p>One important feature of React is error boundaries. They catch and handle errors in the component tree. Without them, unhandled errors may eventually crash the entire application.</p>
<p><strong>Best Practice:</strong> Implement error boundaries using <code>componentDidCatch</code> or <code>ErrorBoundary</code> components.</p>
<pre><code><span class="hljs-keyword">const</span> UserProfile = <span class="hljs-function">(<span class="hljs-params">{ userId }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> [user, setUser] = React.useState(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [error, setError] = React.useState(<span class="hljs-literal">null</span>);

  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    fetch(<span class="hljs-string">`/api/users/<span class="hljs-subst">${userId}</span>`</span>)
      .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
        <span class="hljs-keyword">if</span> (!response.ok) {
          <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Network response was not ok'</span>);
        }
        <span class="hljs-keyword">return</span> response.json();
      })
      .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> setUser(data))
      .catch(<span class="hljs-function"><span class="hljs-params">err</span> =&gt;</span> setError(err.message));
  }, [userId]);

  <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">div</span>&gt;</span>Error: {error}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
  }

  <span class="hljs-keyword">if</span> (!user) {
    <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>{user.name}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};
</code></pre><p>By adding error handling, we catch any issues with the API request and display an appropriate error message. </p>
<p>This approach improves the robustness of the component, providing users with feedback in case of an error and ensuring the application remains functional even when unexpected issues occur.</p>
<h2 id="heading-8-failing-to-keep-components-pure">8. Failing to Keep Components Pure</h2>
<p>React components should always be pure functions of their props. Impure components depend on external states and side effects, making the system unpredictable.</p>
<p><strong>Best Practice:</strong> Ensure that your components are pure and that their output depends entirely on their props.</p>
<pre><code><span class="hljs-keyword">const</span> MyComponent = <span class="hljs-function">(<span class="hljs-params">{ name }</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>{name}<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>;
};
</code></pre><p>This functional component is pure because it only depends on the <code>name</code> prop to render its output.</p>
<h2 id="heading-9-not-using-react-developer-tools">9. Not Using React Developer Tools</h2>
<p>React Developer Tools is a simple yet essential extension for debugging and optimizing the performance of a React application. Development can become more complicated if you don't use this helpful toolkit.</p>
<p><strong>Best Practice:</strong> Install and use React Developer Tools regularly to inspect component hierarchies, state, and props.</p>
<h2 id="heading-10-ignoring-seo-best-practices">10. Ignoring SEO Best Practices</h2>
<p>SEO is an important aspect of any web application, and this holds true for React applications as well. Many developers overlook SEO, leading to poor search engine rankings and reduced visibility.</p>
<p>Here are some of the most common React SEO mistakes:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/tIQv8oIn3g4" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Wondering how to implement the React SEO Best Practices? Good news, I made a follow up video:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/xAFzD1ckPXs" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p><strong>Best Practices:</strong> If video is not your thing, here are the key points to remember:</p>
<ul>
<li>Always <a target="_blank" href="https://www.freecodecamp.org/news/server-side-rendering-javascript/">render your content server-side</a>: Google has publicly stated to avoid Client-Side Rendering (CSR).</li>
<li>Ensure unique URLs for different pages: Since React is a Single Page Application (SPA), always render different URLs for different pages. For example, if you have 5 landing pages, make sure you render 5 unique URLs.</li>
<li>Ensure unique metadata for each page: As a bonus tip, use <a target="_blank" href="https://www.freecodecamp.org/news/react-helmet-examples/">React Helmet</a> to ensure every single page has unique metadata.</li>
<li>Internally link your website: Surprisingly, many developers completely ignore this. Make sure to add internal links to improve navigation and SEO.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, avoiding these common React mistakes can greatly improve the performance and maintainability of your applications. </p>
<p>If you're interested in learning more about my work or need help with React or Next.js development, check out <a target="_blank" href="https://www.hirenext.dev/">hirenext.dev</a>. Alternatively you can keep up with my blog <a target="_blank" href="https://www.ohmycrawl.com/">OhMyCrawl</a>.   </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use React's Context API – Tutorial with Examples ]]>
                </title>
                <description>
                    <![CDATA[ In React, data is typically passed down from parent to child via props. But this can lead to "prop drilling" – where we have to pass props down through lots of components to get them where they're needed. Also, some props (for example, the current au... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/react-context-api-tutorial-examples/</link>
                <guid isPermaLink="false">66c8c99f85ffc69fd028a82c</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React context ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Danny ]]>
                </dc:creator>
                <pubDate>Mon, 22 Jul 2024 15:25:40 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/React.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In React, data is typically passed down from parent to child via props. But this can lead to "prop drilling" – where we have to pass props down through lots of components to get them where they're needed.</p>
<p>Also, some props (for example, the current authenticated user, UI theme, or preferred language) will be required by many components within an application.</p>
<p>React's Context API provides a way to share values like these between components without having to explicitly pass them down as a prop through every level of the tree. So, Context is designed to share data that can be considered "global" for a tree of React components.</p>
<h2 id="heading-what-youll-learn-in-this-article">What You'll Learn in This Article</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-the-react-context-api-and-when-should-you-use-it">What is the React Context API and when should you use it?</a></li>
<li><a class="post-section-overview" href="#heading-react-context-api-example-light-and-dark-mode-ui-theme">React Context API example: how to switch between light and dark mode UI themes</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-multiple-react-contexts">How to create multiple React Contexts (and why you should)</a></li>
<li><a class="post-section-overview" href="#heading-how-to-prevent-the-react-context-re-render-issue">How to prevent the React Context re-render issue</a></li>
<li><a class="post-section-overview" href="#heading-react-context-api-vs-redux">React Context API vs Redux for global state management</a></li>
</ul>
<h2 id="heading-source-code">Source Code</h2>
<p>All examples from this article are in this repo: https://github.com/DoableDanny/React-context-API-tutorial</p>
<p>I also made a video version of this article to make it easier for you to follow along with the examples: <a target="_blank" href="https://www.youtube.com/watch?v=hkGiP6Ur-B4">React Context Tutorial with Examples
</a></p>
<h2 id="heading-what-is-the-react-context-api-and-when-should-you-use-it">What is the React Context API and When Should You Use It?</h2>
<p>The Context API is a feature in React that provides a way to share values like themes, user information, or configuration settings between components without having to explicitly pass props through every level of the component tree. This makes it particularly useful for managing global state, or state that is needed by many components at different nesting levels.</p>
<p>The Context API is a part of the React library, meaning that you don't need to install it as a third-party package in a React application.</p>
<p>So, the Context API can be used for sharing global variables between components in a React app, without having to pass these variables as props down the component tree. This is especially useful if there are components that are deeply nested that need access to variables from higher up components.</p>
<p>Now, let's learn how the Context API works by going through a common use case example for the Context API...</p>
<h2 id="heading-react-context-api-example-light-and-dark-mode-ui-theme">React Context API Example — Light and Dark Mode UI Theme</h2>
<p>A very common real-world usecase for the React Context API is for storing the current user's prefered theme – that is, "light mode" or "dark mode".</p>
<p>Think about it: many of the UI components in a React app will need to know about the current theme, in order to display the approprate styles. Buttons, Headings, the Navbar, the Footer, Dropdowns – lots of components are going to need to display themselves differently depending on the current theme.</p>
<h3 id="heading-the-passing-down-a-prop-solution">The passing-down-a-prop solution</h3>
<p>The most simple and obvious "React" way to solve this would be to create a <code>theme</code> variable in the main top-level <code>App</code> component, and then keep on passing it down as a prop to all of the components in the tree. But this leads to a React problem known as "prop drilling".</p>
<p>Prop drilling is a term used in React to describe the process of passing data from a parent component to a deeply nested child component through multiple intermediary components. This can happen when you need to pass state or functions several levels down the component tree.</p>
<p>Prop drilling example:</p>
<pre><code class="lang-jsx">
<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> theme = <span class="hljs-string">'dark'</span>;
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Parent</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Parent</span>(<span class="hljs-params">{ theme }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Child</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Child</span>(<span class="hljs-params">{ theme }</span>) </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">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span></span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params">{ theme }</span>) </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">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">background:</span> <span class="hljs-attr">theme</span> === <span class="hljs-string">'dark'</span> ? '<span class="hljs-attr">black</span>' <span class="hljs-attr">:</span> '<span class="hljs-attr">white</span>' }}&gt;</span>Click me<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
}
</code></pre>
<p>As you can see, each intermediary component needs to include the prop, even if it doesn't use it, just to pass it down further. This clutters the code and makes it more difficult to understand. </p>
<p>Also, intermediary components that do not use the props might still re-render when the props change, leading to performance issues. This can be particularly problematic in large applications with deep component trees.</p>
<h3 id="heading-context-api-to-the-rescue">Context API To The Rescue</h3>
<p>We can solve this prop drilling issue by using the Context API.</p>
<h4 id="heading-creating-a-context">Creating a context</h4>
<p>First, we need to create the context, and pass in the light theme as the default value:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/contexts/ThemeContext.js</span>

<span class="hljs-keyword">import</span> { createContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> themes = {
  <span class="hljs-attr">light</span>: {
    <span class="hljs-attr">background</span>: <span class="hljs-string">"white"</span>,
    <span class="hljs-attr">text</span>: <span class="hljs-string">"black"</span>,
  },
  <span class="hljs-attr">dark</span>: {
    <span class="hljs-attr">background</span>: <span class="hljs-string">"black"</span>,
    <span class="hljs-attr">text</span>: <span class="hljs-string">"white"</span>,
  },
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ThemeContext = createContext(themes.light);
</code></pre>
<p>Above, we have created a <code>contexts</code> folder inside of our <code>src</code> folder for storing all of our contexts. It's considered good practice to create each context in its own file. In our case, we just need to create a context for storing the current theme.</p>
<p>Notice that contexts are created by calling the <code>createContext()</code> function that comes from the <code>React</code> library. We pass the <code>createContext()</code> function a default value of <code>themes.light</code>.</p>
<h4 id="heading-providing-a-context">Providing a context</h4>
<p>Next, we need to wrap all of the components that need access to the theme in a context provider. The context provider takes a <code>value</code> prop, where we can pass the value that we want to make global. </p>
<p>Below, <code>&lt;Navbar /&gt;</code> and <code>&lt;Button /&gt;</code> will have access to the <code>theme</code> state, even though we haven't explicitly passed it down as a prop. This is because we have wrapped these components in the theme context provider, and passed it the value (<code>theme</code>) that needs to be made global.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/App.js</span>

<span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { ThemeContext, themes } <span class="hljs-keyword">from</span> <span class="hljs-string">"./contexts/ThemeContext"</span>
<span class="hljs-keyword">import</span> Navbar <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Navbar"</span>
<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/Button"</span>

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [theme, setTheme] = useState(themes.light)

  <span class="hljs-keyword">const</span> toggleTheme = <span class="hljs-function">() =&gt;</span> {
    setTheme(<span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> (state === themes.light ? themes.dark : themes.light))
  }

  <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">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ThemeContext.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{theme}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">changeTheme</span>=<span class="hljs-string">{toggleTheme}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ThemeContext.Provider</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 we also wanted to make <code>setTheme()</code> available throughout our app via context, we could pass the following object to the <code>value</code> prop. We'd then be able to toggle the theme from any component within the Theme Context Provider:</p>
<pre><code class="lang-jsx">&lt;ThemeContext.Provider value={{ theme, setTheme }}&gt;
</code></pre>
<p>Now let's create the <code>Button</code> and <code>Navbar</code> components that will consume the theme context using the <code>useContext()</code> hook. Notice how the CSS styles of the components change depending on the current theme values:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/Button.js</span>

<span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { ThemeContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"../contexts/themeContext"</span>

<span class="hljs-keyword">const</span> Button = <span class="hljs-function">(<span class="hljs-params">{ changeTheme }</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> theme = useContext(ThemeContext)

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
      <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">backgroundColor:</span> <span class="hljs-attr">theme.background</span>, <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}
      <span class="hljs-attr">onClick</span>=<span class="hljs-string">{changeTheme}</span>
    &gt;</span>
      Toggle theme
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Button
</code></pre>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/Navbar.js</span>

<span class="hljs-keyword">import</span> React, { useContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { ThemeContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"../contexts/themeContext"</span>

<span class="hljs-keyword">const</span> Navbar = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> theme = useContext(ThemeContext)

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">backgroundColor:</span> <span class="hljs-attr">theme.background</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">li</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>About<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">nav</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Navbar
</code></pre>
<p><strong>Here are the steps involved in using a context</strong>:</p>
<ol>
<li>Import the context that you want to use (<code>ThemeContext</code> in this example) into the component. </li>
<li>Import the <code>useContext</code> hook from <code>React</code>.</li>
<li>Inside of the component that needs access to the context value(s), call the <code>useContext</code> hook and pass the context that you want to use. Assign this to a variable (<code>const theme = useContext(ThemeContext)</code> in our example)</li>
<li>The component now has access to the global variable, and the component will re-render/be updated every time a value inside of the context is updated.</li>
</ol>
<p>OK, that's everything that we need for this example. Let's now start up our application by running the following command in the project route:</p>
<p><code>npm run start</code></p>
<p>Now let's test things out in the browser.</p>
<p>Light mode:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/light_mode.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em><strong> Press the Toggle Theme button </strong></em></p>
<p>Dark mode:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/dark_mode.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And there we go, we've used the context API to share the theme state throughout our application – without having to pass it down as a prop. Cool! 👌</p>
<h2 id="heading-how-to-create-multiple-react-contexts">How to Create Multiple React Contexts</h2>
<p>In our example above, we only created one context, <code>ThemeContext</code>. But what if we had other data that needed to be made global, such as the current logged in user's <code>username</code> and <code>age</code>?</p>
<p>We could just create one big context for storing all variables that needed to be consumed globally:</p>
<pre><code class="lang-jsx">&lt;OneBigContext.Provider value={{ theme, username, age }}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">changeTheme</span>=<span class="hljs-string">{toggleTheme}</span> /&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span></span>
&lt;/OneBigContext.Provider&gt;
</code></pre>
<p>But this is considered bad practice, as whenever a context value is updated, all components consuming that context will be re-rendered. This means that all components that only need to know about the <code>theme</code>, and not the user variables, will get re-rendered whenever any of the user variables are updated. This can worsen an app's performance, especially in larger apps with lots of complex components.</p>
<p>We can solve this by creating multiple contexts – one context for the theme and another for the user data – and wrapping our app in both providers, like so:</p>
<pre><code class="lang-jsx">&lt;ThemeContext.Provider value={theme}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserContext.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">username</span>, <span class="hljs-attr">age</span> }}&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">changeTheme</span>=<span class="hljs-string">{toggleTheme}</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Navbar</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">UserContext.Provider</span>&gt;</span></span>
&lt;/ThemeContext.Provider&gt;
</code></pre>
<p>By only storing related data in each context, we help prevent unnecessary re-renders of components, and improve the performance of our app.</p>
<h2 id="heading-how-to-prevent-the-react-context-re-render-issue">How to Prevent the React Context Re-render Issue</h2>
<p>As we've discussed, whenever a context value is updated, all components consuming that context will be rerendered – even if wrapped in <code>React.memo()</code>. (If you don't know what <code>React.memo()</code> is, don't panic – we'll discuss it soon!) This can worsen an app’s performance. </p>
<p>But we can mitigate this problem with the following methods:</p>
<h3 id="heading-1-use-multiple-react-contexts">1. Use Multiple React Contexts</h3>
<p>This is what we discussed above, and is the "preferred" way of solving the rerender problem (<a target="_blank" href="https://github.com/facebook/react/issues/15156#issuecomment-474590693">see this answer</a>).</p>
<h3 id="heading-2-split-the-component-and-pass-the-needed-value">2. Split the Component and Pass the Needed Value</h3>
<p>You can also split the component up and pass down (as a prop) the needed value from context, with the child components wrapped in <code>React.memo()</code>. Example:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Card = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> appContextValue = useContext(AppContext);
  <span class="hljs-keyword">const</span> theme = appContextValue.theme;

  <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">CardTitle</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">CardDescription</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">const</span> CardTitle = React.memo(<span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>This is the Title <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>;
});

<span class="hljs-keyword">const</span> CardDescription = React.memo(<span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>lorem ipsum dolor sit amet,<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
});
</code></pre>
<p><code>React.memo()</code> is a higher-order component (HOC) in React that is used to optimize functional components by preventing unnecessary re-renders. It does this by memoizing the component, meaning it will only re-render if its props change.</p>
<ul>
<li>Without <code>React.memo()</code>: The components, <code>CardTitle</code> and <code>CardDescription</code>, would re-render whenever their parent, <code>Card</code>, re-renders – even if their props haven't changed. This can lead to performance issues in larger applications or with components that are expensive to render.</li>
<li>With <code>React.memo()</code>: <code>CardTitle</code> and <code>CardDescription</code> only re-render if their props change, reducing unnecessary renders and improving performance.</li>
</ul>
<p>So, by splitting the component up, passing down only the values that are needed as props, and wrapping the components in <code>React.memo()</code>, <code>CardTitle</code> and <code>CardDescription</code> will only be re-rendered if <code>theme</code> is updated, but not if <code>username</code> is updated. </p>
<p>This solution is particularly useful if we can’t split out context for whatever reason.</p>
<h3 id="heading-3-one-component-with-reactusememo-inside">3. One Component with <code>React.useMemo()</code> Inside</h3>
<p>Below, <code>theme</code> is a dependency of <code>useMemo()</code>, so we will only get a re-render of the elements returned by the callback function when <code>theme</code> is changed:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Card = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> appContextValue = useContext(AppContext);
  <span class="hljs-keyword">const</span> theme = appContextValue.theme;

  <span class="hljs-keyword">return</span> useMemo(
    <span class="hljs-function">() =&gt;</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">CardTitle</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">CardDescription</span> <span class="hljs-attr">theme</span>=<span class="hljs-string">{theme}</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    ),
    [theme]
  );
};

<span class="hljs-keyword">const</span> CardTitle = <span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>This is the Title <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span></span>;
};

<span class="hljs-keyword">const</span> CardDescription = <span class="hljs-function">(<span class="hljs-params">{ theme }</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">color:</span> <span class="hljs-attr">theme.text</span> }}&gt;</span>lorem ipsum dolor sit amet,<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>;
};
</code></pre>
<p>Here's how <code>useMemo()</code> works:</p>
<ol>
<li>The first parameter of <code>useMemo()</code> is a callback function that returns a memoized value. In this case, it returns a React element, or tree of React elements.</li>
<li>The second parameter is an array of dependences. If any of the values in this dependency array are updated, then the callback function provided as the first argument is called, and the elements that the callback function returns are re-rendered.</li>
</ol>
<p>So, <code>useMemo()</code> can be used to only re-render React elements if certain values specified in the dependency array are updated.</p>
<p>By wrapping these elements in <code>useMemo()</code>, and specifying <code>theme</code> as the only dependency, the elements only get re-rendered if <code>theme</code> is updated, but won't get re-rendered if any other context value is updated.</p>
<p>This solution is also particularly useful if we can’t split out context.</p>
<h2 id="heading-react-context-api-vs-redux">React Context API vs Redux</h2>
<p>This is a very common and much-depated topic within the React community. React Context API and Redux are both tools for managing state in a React application, but they have different use cases, strengths, and limitations. </p>
<p>The Context API is a built-in feature of React, with the primary purpose of allowing state to be shared across a tree of React components without prop drilling.</p>
<p>The Context API has a simple API: <code>React.createContext()</code>, <code>Provider</code>, and the <code>useContext()</code> hook. And is good for small to medium-sized apps, as it is straightforward to use, and requires little setup and boilerplate code.</p>
<p>On the other hand, Redux is a state management library that has to be installed as a third-party package into an application. Its primary purpose is to manage application-wide state in a predictable way, especially in large and complex applications.</p>
<h4 id="heading-why-context-api-is-good-for-small-to-medium-sized-apps">Why Context API is good for small-to-medium-sized apps:</h4>
<ul>
<li><strong>Simplicity</strong>: It's simpler than Redux.</li>
<li><strong>Built-in</strong>: It's part of React, so no need to install extra packages, making maintenance of the project easier.</li>
<li><strong>Minimal boilerplate</strong>: Requires less boilerplate and setup than Redux.</li>
</ul>
<h4 id="heading-why-redux-is-good-for-larger-more-complex-applications">Why Redux is good for larger, more complex applications:</h4>
<ul>
<li><strong>Single Store</strong>: Maintains a single store for the entire application state, which makes debugging and testing easier.</li>
<li><strong>Predictable State Updates</strong>: Uses pure functions (reducers) to manage state updates, ensuring predictability and immutability.</li>
<li><strong>Middleware Support</strong>: Powerful middleware system (like redux-thunk or redux-saga) for handling asynchronous actions and side effects.</li>
<li><strong>DevTools Integration</strong>: Excellent developer tools for time-travel debugging and state inspection.</li>
<li><strong>Suitable for Large Apps</strong>: Designed to handle complex state logic and large-scale applications.</li>
</ul>
<p><strong>Redux maintainer, <a target="_blank" href="https://x.com/acemarke?lang=en">Mark Erikson</a>, gives the following reasons for using Redux</strong>:</p>
<ul>
<li>Consistent architectural patterns</li>
<li>Debugging capabilities</li>
<li>Middleware</li>
<li>Addons and extensibility</li>
<li>Cross-platform and cross-framework usage</li>
<li>Depending on your app's setup, much better performance than working with just Context (we don't have to worry about the rerender problem we get with Context, mentioned above – components only rerender when the value they are using updates)</li>
</ul>
<h4 id="heading-in-summary">In summary:</h4>
<ul>
<li>Redux is a more complex state management tool that provides more features and tools. It provides a consistent way of managing state throughout an application, which is very helpful on larger projects with multiple developers (as they won't all be implementing their own styles of state management and making the codebase inconsistent).</li>
<li>React Context API is more straightforward, requires less setup, and is a good solution for smaller to medium sized projects where the added complexity and overhead of using a tool like Redux isn't necessary.</li>
</ul>
<h2 id="heading-thank-you-for-reading">Thank you for reading!</h2>
<p>If you found this article useful, you can hear more from me by:</p>
<ul>
<li><a target="_blank" href="https://www.youtube.com/channel/UC0URylW_U4i26wN231yRqvA">Subscribing to my YouTube channel</a>. I plan to turn it into a React/NextJS/Node-focused channel, with in-depth videos 😎.</li>
<li><a target="_blank" href="https://twitter.com/doabledanny">Following me on Twitter</a> where I tweet about my freelancing journey, side projects and current learnings.</li>
<li><a target="_blank" href="https://www.doabledanny.com/blog/">Checking out my tech blog</a></li>
</ul>
<h3 id="heading-free-react-hooks-course">Free React Hooks Course</h3>
<p>Want to learn all the hooks in React? I created a free 2 hour video explaining all 9 core React Hooks with examples: <a target="_blank" href="https://www.youtube.com/watch?v=TXN6HYGLba4&amp;ab_channel=DoableDanny">React Hooks Tutorial — All React Hooks Explained with Examples</a>. If you enjoy, consider subscribing to <a target="_blank" href="https://www.youtube.com/channel/UC0URylW_U4i26wN231yRqvA">my channel</a>.</p>
<p>Cheers!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What's the Difference Between the useMemo and useCallback Hooks? ]]>
                </title>
                <description>
                    <![CDATA[ React provides various hooks that make it easier to manage application state and other React features in functional components. Hooks provide class component features to functional components, and they don't need a lot of code compared to class compo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/difference-between-usememo-and-usecallback-hooks/</link>
                <guid isPermaLink="false">66d8514dec0a9800d5b8e6ea</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react hooks ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kunal Nalawade ]]>
                </dc:creator>
                <pubDate>Mon, 15 Jul 2024 19:14:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/photo-1619410283995-43d9134e7656.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>React provides various hooks that make it easier to manage application state and other React features in functional components. Hooks provide class component features to functional components, and they don't need a lot of code compared to class components.</p>
<p>Hooks also make your life easier by providing some convenient features. Among these hooks, we have <code>useMemo</code> and <code>useCallback</code> that help improve your website's performance.</p>
<p>In today's tutorial, we are going to discuss both the <code>useMemo</code> and <code>useCallback</code> hooks. You'll learn the difference between them and when to use each hook.</p>
<h2 id="heading-the-usememo-hook">The <code>useMemo</code> Hook</h2>
<p>The <code>useMemo</code> hook <em>memoizes</em> the return value of an expensive calculation between renders. Memoizing means storing the value as a cached value so that the value need not be calculated again (unless it's required).</p>
<p><code>useMemo</code> is a hook used for optimising the performance of your renders. Normally, when you declare a variable inside a component, it gets re-created on every render. If it stores the return value of a function, then the function gets called every time your component renders.</p>
<p>Normally, this wouldn't be a problem. But, what if the function is expensive? What if it takes a longer time to execute? Take the following example:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">calculate</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> result = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000000000</span>; i++) {
    result += i;
  }
  <span class="hljs-keyword">return</span> result;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App1</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

  <span class="hljs-keyword">const</span> value = calculate();

  <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">"App"</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> setCount(count + 1)}&gt;Increment Count<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Count: {count}<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>
<p>When you click on 'Increment Count', it takes a few seconds to update the count state. This is because the <code>calculate</code> function runs every time a component re-renders after state change.</p>
<p>Now, imagine if there were multiple state variables in the component, each serving its own purpose. Each state update would cause a re-render and execute this expensive function.</p>
<p>These state variables could be completely unrelated to the expensive calculation performed, which would cause unnecessary delays. This would affect the performance of your website and could lead to a terrible user experience.</p>
<p><code>useMemo</code> can help you tackle this issue. Let's first understand its syntax:</p>
<pre><code class="lang-python">const value = useMemo(expensiveFunction, [...dependencyArray])
</code></pre>
<p>The <code>useMemo</code> hook should be declared at the top level of your component. It takes the following arguments:</p>
<ul>
<li><p><code>expensiveFunction</code> contains the expensive calculation you want to perform. If you have declared the function outside, pass the function reference only, without the brackets. You can also pass arrow functions directly.</p>
</li>
<li><p><code>dependencyArray</code> contains list of dependencies for the hook. The expensive function will be called only when one of these dependencies is updated. You can pass state variables or props that are dependent on this calculation. Any other state updates will not trigger the function.</p>
</li>
</ul>
<p>On the first render, <code>useMemo</code> returns the result of <code>expensiveFunction</code> and caches the result. During the subsequent renders, it will return the cached value if no dependencies have changed. If they change, then it will call the function again.</p>
<p>Let's use this in our case:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [dependentCount, setDependentCount] = useState(<span class="hljs-number">10</span>);

<span class="hljs-keyword">const</span> value = useMemo(calculate, [dependentCount]);

<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">"App"</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> setDependentCount(dependentCount + 1)}&gt;
      Increment Dependent Count
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Dependent Count: {dependentCount}<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>
<p>We have created another state <code>dependentCount</code> that we assume is dependent on the expensive calculation. When this state updates and renders the component, the <code>calculate</code> function will run.</p>
<p>But if any other state changes, then <code>useMemo</code> will return the cached value instead of running the function again.</p>
<p>Let's test this by adding a <code>console.log</code> inside the function:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-28.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Output with useMemo</em></p>
<p>Now, when you click "Increment Count", the rendering is faster, since the <code>calculate</code> function is not getting called on every render. This is the same during every other state update not listed in the useMemo dependency array.</p>
<p>But when you click on "Increment dependent Count", it takes time to render the updated value. This is because <code>dependentCount</code> is a dependency of <code>useMemo</code> and changing it calls the expensive function, so the component takes time to re-render.</p>
<p>In this way, with <code>useMemo</code>, you can control the execution of an expensive function by calling it only for state updates that actually need the value returned. This can drastically improve your app's performance.</p>
<h3 id="heading-when-to-use-usememo">When to use <code>useMemo</code>:</h3>
<ul>
<li><p>When you have a state dependent on an expensive calculation, but you don't want to run the calculation on every render.</p>
</li>
<li><p>When you declare an array or object inside a component, its reference changes on every render, even though the value remains the same. Wrapping the values inside <code>useMemo</code> maintains referential equality and prevents unnecessary re-renders. This is essential when there's a <code>useEffect</code> dependent on the array or object.</p>
</li>
<li><p>When you are rendering lists using <code>Array.map</code> that do not need to change unless a certain state value changes.</p>
</li>
</ul>
<h2 id="heading-the-usecallback-hook">The <code>useCallback</code> Hook</h2>
<p>Similar to <code>useMemo</code>, you can also use this hook to optimise performance. The <code>useCallback</code> hook memoizes a callback function and returns it.</p>
<p>Note that the <code>useCallback</code> hook memoizes the function itself, not its return value. <code>useMemo</code> caches the functions return value so that the function need not execute again. <code>useCallback</code> caches the function definition or the function reference.</p>
<p>A function declared inside a component gets re-created on every component render, similar to a variable. The difference is, it gets rendered with a different reference every time. So, a <code>useEffect</code> dependent on this function will execute again on each render. A similar thing happens with child components.</p>
<p>Let's take an example:</p>
<pre><code class="lang-python">const App = () =&gt; {
  const [count, setCount] = useState(<span class="hljs-number">0</span>);
  const [value, setValue] = useState(<span class="hljs-string">""</span>);

  const handleClick = () =&gt; {
    setValue(<span class="hljs-string">"Kunal"</span>);
  };
  <span class="hljs-keyword">return</span> (
    &lt;div className=<span class="hljs-string">"App"</span>&gt;
      &lt;button onClick={() =&gt; setCount(count + <span class="hljs-number">1</span>)}&gt;Increment Count&lt;/button&gt;
      &lt;p&gt;Count: {count}&lt;/p&gt;
      &lt;p&gt;Value: {value}&lt;/p&gt;
      &lt;SlowComponent handleClick={handleClick} /&gt;
    &lt;/div&gt;
  );
};

const SlowComponent = React.memo(({ handleClick, value }) =&gt; {

  // Intentially making the component slow
  <span class="hljs-keyword">for</span> (let i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000000000</span>; i++) {}

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h1&gt;Slow Component&lt;/h1&gt;
      &lt;button onClick={handleClick}&gt;Click Me&lt;/button&gt;

    &lt;/div&gt;
  );
});
</code></pre>
<p>Here, we have a <code>SlowComponent</code> as the child of the <code>App</code> component. When a parent component renders, all of its child components render, regardless of whether anything has changed inside them.</p>
<p>To avoid unnecessary renders of the child components, we generally use the <code>React.memo</code> function. This basically caches the component and only re-renders it if its props have changed.</p>
<p>Now, when you click on 'Increment Count', it still takes a long time to render, because <code>SlowComponent</code> re-renders on state change. But why is that? We're not changing any of its props.</p>
<p>On the surface, we may not appear to change the value of <code>handleClick</code> prop. But, since functions are re-created with a different reference, on every render of the App component, its child (that is <code>SlowComponent</code>) renders.</p>
<p>To maintain referential equality, we wrap this function's definition inside a <code>useCallback</code>.</p>
<p>Let's understand its syntax:</p>
<pre><code class="lang-python">const cachedFn = useCallback(fn, [...dependencyArray])
</code></pre>
<p><code>useCallback</code> takes the following arguments:</p>
<ul>
<li><p><code>fn</code> is the function you want to cache. It is the function definition that you want to create, and can take any arguments and return any value.</p>
</li>
<li><p><code>dependencyArray</code> is a list of dependencies, changes to which trigger re-creation of the function. You can pass state values or props that are dependent on this function.</p>
</li>
</ul>
<p>On the first render, React creates the function (does not call it) and caches it. On the subsequent renders, the cached function is returned to you. Remember, this hook returns and caches the <em>function</em> and not its return value.</p>
<p>Let's use this hook in our example:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> { useCallback } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

const App = () =&gt; {

  // ...

  const handleClick = useCallback(() =&gt; {
    setValue(<span class="hljs-string">"Kunal"</span>);
  }, [value, setValue]);

  // ...
};
</code></pre>
<p>Here, we have wrapped the function inside a <code>useCallback</code> and passed two dependencies that are involved with this function.</p>
<p>Now, when you click on 'Increment Count', the rendering is much faster. This is because the <code>handleClick</code> reference is cached between renders and hence, <code>SlowComponent</code> does not re-render.</p>
<p>But when you click on the button inside <code>SlowComponent</code> it will re-render. This is because when the <code>value</code> state changes, the <code>handleClick</code> method is created again and so the props of the slow component have changed.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-33.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Value takes time to render</em></p>
<p>You can add many more states to the <code>App</code> component and update them without inhibiting performance as long as you don't update <code>value</code>'s state.</p>
<h3 id="heading-when-to-use-usecallback">When to use <code>useCallback</code></h3>
<ul>
<li><p>When you have event handlers defined for an element inside your component, wrap them inside a <code>useCallback</code> to avoid unnecessary re-creations of event handlers.</p>
</li>
<li><p>When you call a function inside a <code>useEffect</code>, you usually pass the function as a dependency. To avoid using <code>useEffect</code> unnecessarily on every render, wrap the function definition inside a <code>useCallback</code>.</p>
</li>
<li><p>If you are writing a custom hook, and it returns a function, it is recommended to wrap it inside a <code>useCallback</code>. So, there's no need for the users to worry about optimizing the hook – rather, they can focus on their own code.</p>
</li>
</ul>
<h2 id="heading-differences-between-usememo-and-usecallback">Differences Between <code>useMemo</code> and <code>useCallback</code></h2>
<p>Let's summarize the differences between the two hooks:</p>
<ul>
<li><p><code>useMemo</code> caches the return value of a function. <code>useCallback</code> caches the function definition itself.</p>
</li>
<li><p><code>useMemo</code> is used when you have an expensive calculation you want to avoid on every render.</p>
</li>
<li><p><code>useCallback</code> is used to cache a function to avoid re-creating it on every re-render.</p>
</li>
<li><p><code>useMemo</code> makes sure that an expensive function should only be called for state values dependent on it.</p>
</li>
<li><p><code>useCallback</code> creates stable functions that maintain the same reference between renders. This avoids unnecessary rendering of child components.</p>
</li>
</ul>
<p>And here are a few more things to remember. Use these hooks only if you want to memoize expensive calculations or prevent unnecessary re-renders. Do not use <code>useMemo</code> and <code>useCallback</code> everywhere.</p>
<p>For regular functions, these hooks don't make much difference. Overusing them will make your code unreadable. Instead, you can figure out other ways to improve app performance.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p><code>useMemo</code> and <code>useCallback</code> are useful hooks in React that can help you optimize performance of your web app. It is important to understand the difference between the two and their usages.</p>
<p>In this article, we have discussed how both hooks work. <code>useMemo</code> caches the result of an expensive calculation, while <code>useCallback</code> caches the function reference. We also listed down scenarios when you should use each hook. Together, both these hooks can make your website faster.</p>
<p>I hope this article helps clear up any confusion. If you have further questions or comments regarding the post, reach out to me on Twitter. I would love to hear suggestions. Till next time, goodbye!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Upgrade from Node 16 and Jest 26 While Staying on React Scripts 4 ]]>
                </title>
                <description>
                    <![CDATA[ Recently, I was trying to upgrade some of my open source projects. They were made using create-react-app around 2019, and I wanted to upgrade to a newer version of NodeJS and Jest. This would let me take advantage of the security updates, bug fixes, ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-upgrade-node-and-jest-while-on-react-scripts-v4/</link>
                <guid isPermaLink="false">66b9e801748589d7de3c86ab</guid>
                
                    <category>
                        <![CDATA[ Jest ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Harsh Deep ]]>
                </dc:creator>
                <pubDate>Wed, 10 Jul 2024 19:35:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/image0.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Recently, I was trying to upgrade some of my open source <a target="_blank" href="https://github.com/classtranscribe/FrontEnd/">projects</a>. They were made using <a target="_blank" href="https://github.com/facebook/create-react-app">create-react-app</a> around 2019, and I wanted to upgrade to a newer version of NodeJS and Jest. This would let me take advantage of the security updates, bug fixes, speed improvements, and new features that the ecosystem has developed since then. </p>
<p>Unfortunately, it was not as simple as just running <code>$ nvm use 18</code> and sailing into the sunset. Luckily, if you follow all the proper steps, you'll get past many significant hurdles and upgrade successfully. In this guide, I will share all the knowledge I wish I had known going into the process. The goal is to get your React application using Node 18+ and Jest 29+ while not making the treacherous upgrade to React Scripts 5.</p>
<p>If you can upgrade to React Scripts 5 (which is impractical for most real-world applications), I highly recommend that path instead. This is because the newest version of CRA fixes many issues with older dependencies, like the <code>MD4 envelope</code> or Babel <code>process()</code> return shapes, that we'll manually tackle in this tutorial. If you can upgrade to v5, then Node versions 18+ should work out of the box.</p>
<p>Unfortunately, going up to React Scripts 5 introduces many breaking changes, mostly due to the upgrade to Webpack 5. While many small/tutorial-level applications can upgrade fairly easily, any real-world application faces a steep uphill journey to upgrade. </p>
<p>If the React Scripts 5 upgrade approach doesn't work for you, you can follow what I've written below on making the Node upgrade work while still staying on React Scripts 4. At the end of this page, I've written a small note about my journey trying the <code>v5</code> upgrade.</p>
<p>Everyone's upgrade journey will vary, especially considering the Jenga of <code>npm</code> dependencies and the relative lack of maintenance of Create React App's React Scripts in recent years.</p>
<p>These are the steps of the upgrade that I've tried with a few different React applications, but you may encounter issues I didn't encounter myself. Google is your best friend in these cases, and it will often lead you to Stackoverflow, GitHub issues, other tutorials, and maybe even source code. Don't be afraid; you'll be able to figure it out! </p>
<p>Note: In this tutorial, I'll refer to Create React App as CRA. React Scripts is the name of the installed package that abstracts all the configuration created by the Create React App command, and in most cases you'll see online resources use both interchangeably.</p>
<h2 id="heading-table-of-contents">Table Of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-how-to-validate-every-step">How to Validate Every Step</a></li>
<li><a class="post-section-overview" href="#heading-how-to-bump-to-react-scripts-v403">How to Bump to React Scripts v4.0.3</a></li>
<li><a class="post-section-overview" href="#heading-how-to-bump-node-version-to-18">How to Bump Node Version to 18</a><br>– <a class="post-section-overview" href="#heading-understanding-the-md4-issue">Understanding the MD4 Issue</a></li>
<li><a class="post-section-overview" href="#heading-how-to-eject-out-of-react-scripts">How to Eject Out of React Scripts</a><br>– <a class="post-section-overview" href="#heading-how-to-add-linter-ignores-for-ejected-files">How to Add Linter Ignores For Ejected Files</a><br>– <a class="post-section-overview" href="#heading-how-to-update-your-dockerfile-and-other-build-processes-with-the-ejected-folders-1">How to update your Dockerfile and Other Build Processes with the ejected folders</a><br>– <a class="post-section-overview" href="#heading-how-to-fix-absolute-paths-for-jest">How to Fix Absolute Paths for Jest</a><br>– <a class="post-section-overview" href="#heading-how-to-update-your-dockerfile-and-other-build-processes-with-the-ejected-folders-1">How to update your Dockerfile and Other Build Processes with the ejected folders</a></li>
<li><a class="post-section-overview" href="#heading-how-to-override-webpack-md4-to-sha256">How to Override Webpack MD4 to SHA256</a></li>
<li><a class="post-section-overview" href="#heading-how-to-upgrade-to-the-latest-version-of-jest">How to Upgrade to the Latest Version of Jest</a><br>– <a class="post-section-overview" href="#heading-how-to-bump-to-jest-28">How to Bump to Jest 28</a><br>– <a class="post-section-overview" href="#heading-how-to-explicitly-set-jsdom-as-the-test-environment">How to explicitly set jsdom as the test environment</a><br>– <a class="post-section-overview" href="#heading-how-to-fix-transformer-return-type-for-process-and-processasync">How to Fix Transformer Return Type for process() and processAsync()</a><br>– <a class="post-section-overview" href="#heading-how-to-bump-jest-to-29">How to Bump Jest to 29</a></li>
<li><a class="post-section-overview" href="#heading-how-far-should-i-upgrade-nodejs">How Far Should I Upgrade NodeJS?</a></li>
<li><a class="post-section-overview" href="#heading-should-you-still-use-create-react-scripts-what-alternatives-are-there">Should You Still Use Create React Scripts? What Alternatives Are There?</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
<li><a class="post-section-overview" href="#heading-alternatively-how-to-upgrade-to-react-scripts-501">Alternatively: How to Upgrade to React Scripts 5.0.1</a></li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this guide, you should have a React application that is:</p>
<ul>
<li>created with <code>create-react-app</code> v4 or upgraded to use <code>react-scripts</code> v4. I've tested this tutorial on both scenarios.</li>
<li>running on Node 16</li>
</ul>
<p>If you're running NodeJS behind 16, I highly suggest upgrading to version 16. The upgrade path to 16 isn't too bad, but the jump from 16 to 18 creates breaking issues with CRA 4 defaults. </p>
<p>Our application also ran <code>jest</code> (v26), the most common test framework in React and shipped by default in CRA v4. If you aren't running Jest, then you can skip the steps relevant to it.</p>
<p>We were also using <code>yarn</code>, but the process should be identical with different syntax if you use any other runner/package manager like <code>npm</code>.</p>
<p>Ideally, you have some test case coverage to ensure things don't break between versions, so it's well worth taking some time to write some broad integration and unit tests before any upgrade.</p>
<p>I recommend using version control like <code>git</code> for each stage while working on a branch. I started over three different times using different upgrade strategies until I had something that worked. Here's a quick <a target="_blank" href="https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell">intro</a> to <code>git</code> branches if you're unfamiliar with them.</p>
<p>I also recommend using <a target="_blank" href="https://github.com/nvm-sh/nvm">nvm</a> (Node Version Manager) to to swap versions quickly. You don't have to use it, and there are many other alternatives out there to manage versions, but it makes quickly switching very easy with just <code>nvm use</code>. I'll use <code>nvm</code> syntax in this tutorial, but it should be pretty similar for your tool.</p>
<h2 id="heading-how-to-validate-every-step">How to Validate Every Step</h2>
<p>Throughout the tutorial, to ensure things still work, you'll run the following:</p>
<ul>
<li><code>$ yarn build</code> – End-to-end build to catch a lot of library-level issues</li>
<li><code>$ yarn test</code> – Regression tests to catch breaks in functionality</li>
<li><code>$ yarn start</code> – The starter scripts to catch many initialization bugs.</li>
</ul>
<p>If you have any more validation steps (CI builds, Docker, staging environments, smoke tests), make sure they're working already and use them throughout the process to validate the upgrade worked correctly. For the rest of the tutorial, I'll refer to these as validation commands.</p>
<p>Before you start the upgrade, make sure all validation steps are working on your current Node 16 and CRA 4. At the end of the tutorial, all these validation steps should be working too. Ultimately, make sure to actually use your React application extensively as the final test once all the upgrade process is done.</p>
<p>Occasionally, you may need to <code>$ rm -rf node_modules</code> and <code>$ rm package.lock.json</code> / <code>$ rm yarn.lock</code> because some library changes may not propagate correctly. Ideally you won't need to do this, but it's reasonably safe since it just downloads all packages again.</p>
<h2 id="heading-how-to-bump-to-react-scripts-v403">How to Bump to React Scripts v4.0.3</h2>
<p>Depending on when you started your project from CRA, you'll likely be at different versions along v4. First, we upgrade to the latest minor version to smooth over the rest of the upgrade process.</p>
<p>There shouldn't be any major breaking changes between the minor versions, but make sure to upgrade it incrementally in your <code>package.json</code> going from <code>4.0.0</code> -&gt; <code>4.0.1</code> -&gt; <code>4.0.2</code> -&gt; <code>4.0.3</code>. Going to <code>4.0.3</code> will streamline your upgrade process since these minor updates have a lot of useful bug, library, and dependency fixes while not creating new work for now. </p>
<p>I ran <code>$ yarn install</code> after each step and then checked my validation commands to ensure everything was still working.</p>
<pre><code class="lang-json">... 
<span class="hljs-string">"dependencies"</span>: { 
    <span class="hljs-attr">"react-scripts"</span>: <span class="hljs-string">"4.0.1"</span>, 
    ... 
}, 
...
</code></pre>
<p>In my projects, I didn't encounter any issues, but your mileage may vary. The official <a target="_blank" href="https://github.com/facebook/create-react-app/blob/main/CHANGELOG-4.x.md">CRA v4 changelog documentation</a> has a list of small changes and upgrade steps between the versions, which will narrow down the causes.</p>
<h2 id="heading-how-to-bump-node-version-to-18">How to Bump Node Version to 18</h2>
<p>After making sure your validation commands are working on your current Node 16, set your version to 18. Then we work on fixing all the validation commands until all of them work. Occasionally you may switch back to 16 to make sure things still work in the older version. </p>
<p>In your command line, run the following:</p>
<pre><code class="lang-sh">$ nvm install 18
$ nvm use 18
</code></pre>
<blockquote>
<p>Note: If you have a <code>.nvmrc</code> file, you can skip the version numbers in the <code>nvm install</code> and <code>nvm use</code> commands. Update the file as you change node versions.</p>
</blockquote>
<p>Unfortunately, if you try <code>$ yarn start</code> or <code>$ yarn build</code>, you'll immediately run into the cryptography error that comes from <code>openssl</code>, which blocks all encryption using MD4. This is the main error blocking the upgrade to Node 18 while on CRA 4.</p>
<pre><code><span class="hljs-built_in">Error</span>: error:<span class="hljs-number">0308010</span>C:digital envelope routines::unsupported
</code></pre><h3 id="heading-understanding-the-md4-issue">Understanding the MD4 Issue</h3>
<p>MD4 is an old encryption algorithm from the 1990s and has been considered very insecure since 1995 (<a target="_blank" href="https://en.wikipedia.org/wiki/MD4">Wikipedia</a>). OpenSSL from version 3 onward changed MD4 to not be supported by default, but it can be enabled with an allow unsafe legacy <a target="_blank" href="https://github.com/openssl/openssl/issues/21247">flag</a> on your system <code>openssl</code> or <code>--openssl-legacy-provider</code> if adding it to your node/CRA script (see the Node <a target="_blank" href="https://nodejs.org/api/cli.html#--openssl-legacy-provider">docs</a>). </p>
<p>It's a seemingly simple fix to the solution, but this is more of a last resort since allowing unsafe cryptography is generally a bad idea, and OpenSSL has disabled the algorithm entirely for a reason.</p>
<blockquote>
<p>Note: If you're curious, Webpack has a 1000+ response <a target="_blank" href="https://github.com/webpack/webpack/issues/14532">discussion</a> on this topic that might have something useful. Later versions of Webpack also eventually <a target="_blank" href="https://github.com/webpack/webpack/pull/14306">allowed</a> a better algorithm called <a target="_blank" href="https://github.com/Cyan4973/xxHash">xxHash</a>, added a built-in MD4 <code>wasm</code> <a target="_blank" href="https://github.com/webpack/webpack/pull/14584">implementation</a>, and added a new config option called <a target="_blank" href="https://webpack.js.org/configuration/optimization/#optimizationmoduleids">deterministic</a> that sidesteps the issue. </p>
</blockquote>
<p>I highly recommend reading this StackOverflow <a target="_blank" href="https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported">answer</a> for a quick overview of the major options if we aren't patching it ourselves. Since upgrading dependencies isn't possible here, and we don't want to stay on an old Node version or allow insecure algorithms, we need to dive into the internals of CRA to fix it.  </p>
<h2 id="heading-how-to-eject-out-of-react-scripts">How to Eject Out of React Scripts</h2>
<p>CRA is designed for a zero-configuration experience for React Apps that lets you focus on just working on your business logic. </p>
<p>When you want to start changing configuration, CRA doesn't have a built-in method to override any option. Instead, it offers a command called <code>eject</code> that copies over all the internals of CRA to your project while leaving your yarn/npm commands intact and then removing React scripts from your project entirely. It's a one-way action, so make sure you save the previous version in <code>git</code>. </p>
<pre><code class="lang-shell">$ yarn eject
</code></pre>
<p>This is a huge command that will change lots of files in the <code>config/</code> and <code>scripts/</code> directories as well as your list of packages in <code>package.json</code>. Once you rerun <code>yarn install</code>, make sure to run all your validation commands to make sure everything still works on Node 16 since nothing should have changed in terms of functionality.</p>
<p>Alternatively, if you don't want to try <code>eject</code>, there are also workarounds like:</p>
<ul>
<li>CRACO uses a clever override mechanism to allow you to still use React Scripts while customizing. Read <a target="_blank" href="https://craco.js.org/docs/getting-started/">Getting Started</a> and <a target="_blank" href="https://medium.com/workleap/why-i-built-craco-33ff39f4fc94">Why I built CRACO</a>. Start off with version <code>6.4.5</code> for CRA v4.</li>
<li><a target="_blank" href="https://github.com/ds300/patch-package">patch-package</a> applies specific npm package changes for your project and then you share the patch with your team/project. For this guide, you will patch <code>react-scripts</code> with the modified webpack and config setups.</li>
<li>Forking CRA with your own modifications. This way you can still keep the zero config CRA with no hacks to patch in new functionality, but this might get complicated. Here's a guide I saw online: <a target="_blank" href="https://auth0.com/blog/how-to-configure-create-react-app/">Customizing create-react-app: How to Make Your Own Template</a>.</li>
</ul>
<p>There's also <a target="_blank" href="https://github.com/timarney/react-app-rewired">react-app-rewired</a> for a similar purpose, but it's mostly unmaintained right now and intended for older versions of CRA behind v4.</p>
<h3 id="heading-how-to-add-linter-ignores-for-ejected-files">How to Add Linter Ignores for Ejected Files</h3>
<p>A lot of the new files from the ejected configuration might not follow your existing project's linter rules. Until you're done with the upgrade, I recommend just adding new ignores on the top of the failing files like:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* eslint-disable import/order */</span>

<span class="hljs-comment">// rest of file</span>
...
</code></pre>
<p>Once you're done with the entire tutorial, feel free to go back and try fixing some of the linter issues, but it might be okay to leave these files as-is since you'll rarely go in to change anything.</p>
<h3 id="heading-how-to-fix-absolute-paths-for-jest">How to Fix Absolute Paths for Jest</h3>
<p>In your <code>package.json</code>, the jest <code>"testRunner"</code> option might be encoded to the absolute path that only makes sense on your computer. So, you'll want to change it to a path based on your project's root directory. </p>
<p>While this might work fine for your local development, it will break for any collaborators or cloud computers.</p>
<pre><code class="lang-json">... 
<span class="hljs-string">"jest"</span>: { 
    ... 
    <span class="hljs-attr">"testRunner"</span>: <span class="hljs-string">"/my/computer/path/project_name/node_modules/jest-circus/runner.js"</span>, 
    ... 
}, 
...
</code></pre>
<p>We use the option <code>&lt;rootDir&gt;</code> that is provided by <a target="_blank" href="https://jestjs.io/docs/configuration#rootdir-string">Jest</a>:</p>
<pre><code class="lang-json">... 
<span class="hljs-string">"jest"</span>: { 
    ... 
    <span class="hljs-attr">"testRunner"</span>: <span class="hljs-string">"&lt;rootDir&gt;/node_modules/jest-circus/runner.js"</span>, 
    ... 
}, 
...
</code></pre>
<p>You might not have to do this on all projects, but <code>"modulePaths"</code> may need an update as well:</p>
<pre><code class="lang-json">...
<span class="hljs-string">"jest"</span>: { 
    ... 
    <span class="hljs-attr">"modulePaths"</span>: [ <span class="hljs-string">"/my/computer/path/project_name/src"</span> ] 
    ... 
}, 
...
</code></pre>
<p>Just remove the reference to your computer's absolute path:</p>
<pre><code class="lang-json">...
<span class="hljs-string">"jest"</span>: { 
    ... 
    <span class="hljs-attr">"modulePaths"</span>: [ <span class="hljs-string">"src"</span> ] 
    ... 
}, 
...
</code></pre>
<h3 id="heading-how-to-update-your-dockerfile-and-other-build-processes-with-the-ejected-folders">How to Update your Dockerfile and Other Build Processes with the Ejected Folders</h3>
<p>Make sure to include the new ejected folders, <code>scripts/</code> and  <code>config/</code>,  into your <code>Dockerfile</code> and other build processes you might be using that existed outside CRA. </p>
<p>For example, the Dockerfile will have the additions of new directories that CRA created that we also want to copy over.</p>
<pre><code class="lang-dockerfile">... 
<span class="hljs-keyword">COPY</span><span class="bash"> scripts scripts/</span>
<span class="hljs-keyword">COPY</span><span class="bash"> config config/ </span>
...
</code></pre>
<h2 id="heading-how-to-override-webpack-md4-to-sha256">How to Override Webpack MD4 to SHA256</h2>
<p>Based on this <a target="_blank" href="https://stackoverflow.com/a/78005686">StackOverflow answer</a>, we add to <code>webpack.config.js</code> right before we start defining <code>module.exports</code> to use the relatively more modern and secure SHA256 instead of MD4 that's also built into Webpack:</p>
<pre><code class="lang-js"><span class="hljs-comment">// ... </span>
<span class="hljs-comment">// https://stackoverflow.com/a/78005686 </span>
<span class="hljs-keyword">const</span> crypto = <span class="hljs-built_in">require</span>(<span class="hljs-string">"crypto"</span>); 
<span class="hljs-keyword">const</span> crypto_orig_createHash = crypto.createHash; crypto.createHash = <span class="hljs-function"><span class="hljs-params">algorithm</span> =&gt;</span> crypto_orig_createHash(algorithm == <span class="hljs-string">"md4"</span> ? <span class="hljs-string">"sha256"</span> : algorithm); 
<span class="hljs-comment">// This is the production and development configuration. </span>
<span class="hljs-comment">// It is focused on developer experience, fast rebuilds, and a minimal bundle. </span>
<span class="hljs-built_in">module</span>.exports = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">webpackEnv</span>) 
// ...</span>
</code></pre>
<p>Once you've changed this, the envelope errors should disappear and your validation commands should now work for Node 18.</p>
<h2 id="heading-how-to-upgrade-to-the-latest-version-of-jest">How to Upgrade to the Latest Version of Jest</h2>
<p>The <code>eject</code> also exposes the Babel configuration used for making more recent versions of Jest work correctly. This works great for version 26 but moving the CRA config to the latest version (v29 at the time of writing) has a few more steps. </p>
<p>You should go through <code>v26</code> -&gt; <code>v28</code> -&gt; <code>v29</code> (skipping v27) for all the Jest dependencies. This part is optional if you're happy with CRA v4's Jest 26, but until you eject, you're blocked from upgrading to a recent version of Jest.</p>
<p>I'm skipping Jest 27 because it'll require a change in <code>config/jest/babelTransform.js</code> where you'll have to change <code>module.exports = babelJest.default.createTransformer({</code> to <code>module.exports = babelJest.createTransformer({</code>. This was a bug <a target="_blank" href="https://github.com/jestjs/jest/pull/12399">fixed</a> in version 28. Still, if you want to go through Jest 27 as well, you'll be able to follow the rest of the steps with this change and then optionally reverting it on Jest 28.</p>
<p>I also highly recommend reading the introduction articles for each of the Jest version upgrades:</p>
<ul>
<li><a target="_blank" href="https://jestjs.io/blog/2021/05/25/jest-27">Jest 27: New Defaults for Jest, 2021 edition ⏩</a></li>
<li><a target="_blank" href="https://jestjs.io/blog/2022/04/25/jest-28">Jest 28: Shedding weight and improving compatibility 🫶</a></li>
<li><a target="_blank" href="https://jestjs.io/blog/2022/08/25/jest-29">Jest 29: Snapshot format changes</a></li>
</ul>
<p>Most of the issues come from Jest 28 having many breaking changes, but the rest of the upgrade path is fairly straightforward.</p>
<h3 id="heading-how-to-bump-to-jest-28">How to Bump to Jest 28</h3>
<p>For each upgrade, I recommend doing a find and replace for all the many Jest-related packages in your <code>package.json</code> since the version numbers are all synced. Once you update the numbers, just run <code>$ yarn install</code>:</p>
<pre><code class="lang-json">... 
<span class="hljs-string">"devDependencies"</span>: { 
    ...
    <span class="hljs-attr">"babel-jest"</span>: <span class="hljs-string">"^28.1.3"</span>, 
    ...
    <span class="hljs-attr">"jest"</span>: <span class="hljs-string">"^28.1.3"</span>, 
    <span class="hljs-attr">"jest-circus"</span>: <span class="hljs-string">"^28.1.3"</span>, 
    <span class="hljs-attr">"jest-resolve"</span>: <span class="hljs-string">"^28.1.3"</span>, 
    ...
} 
...
</code></pre>
<h3 id="heading-how-to-explicitly-set-jsdom-as-the-test-environment">How to Explicitly Set <code>jsdom</code> as the Test Environment</h3>
<p>If you try running your tests out of the box with <code>$ yarn test</code>. It'll give you this error:</p>
<pre><code>● Validation <span class="hljs-built_in">Error</span>: 
Test environment jest-environment-jsdom cannot be found. 
Make sure the testEnvironment configuration option points to an existing node <span class="hljs-built_in">module</span>. 
Configuration Documentation: https:<span class="hljs-comment">//jestjs.io/docs/configuration </span>
As <span class="hljs-keyword">of</span> Jest <span class="hljs-number">28</span> <span class="hljs-string">"jest-environment-jsdom"</span> is no longer shipped by <span class="hljs-keyword">default</span>, make sure to install it separately.
</code></pre><p>In Jest 27, Jest <a target="_blank" href="https://jestjs.io/blog/2021/05/25/jest-27">changed the default test environment</a> to be meant for a more lightweight NodeJS backend environment. However, we have a frontend application, so we still want to test with a simulated browser environment that older Jest versions were based off called <a target="_blank" href="https://github.com/jsdom/jsdom">jsdom</a>. </p>
<p>To fix this, add <code>"jest-environment-jsdom"</code> to your dependencies and then run <code>$ yarn install</code>.</p>
<pre><code class="lang-json">... 
<span class="hljs-string">"devDependencies"</span>: { 
    ...
    <span class="hljs-attr">"babel-jest"</span>: <span class="hljs-string">"^28.1.3"</span>, 
    ...
    <span class="hljs-attr">"jest"</span>: <span class="hljs-string">"^28.1.3"</span>, 
    <span class="hljs-attr">"jest-circus"</span>: <span class="hljs-string">"^28.1.3"</span>, 
    <span class="hljs-attr">"jest-resolve"</span>: <span class="hljs-string">"^28.1.3"</span>, 
    <span class="hljs-attr">"jest-environment-jsdom"</span>: <span class="hljs-string">"^28.1.3"</span>, 
    ...
} 
...
</code></pre>
<h3 id="heading-how-to-fix-transformer-return-type-for-process-and-processasync">How to Fix Transformer Return Type for <code>process()</code> and <code>processAsync()</code></h3>
<p>‌‌Now, if you run <code>yarn test</code>, you'll get this:</p>
<pre><code>FAIL  src/App.test.js 
● Test suite failed to run 
● Invalid <span class="hljs-keyword">return</span> value: <span class="hljs-string">`process()`</span> or/and <span class="hljs-string">`processAsync()`</span> method <span class="hljs-keyword">of</span> code transformer found at <span class="hljs-string">"path/in/my/computer"</span> 
should <span class="hljs-keyword">return</span> an object or a <span class="hljs-built_in">Promise</span> resolving to an object. The object must have <span class="hljs-string">`code`</span> property <span class="hljs-keyword">with</span> a string <span class="hljs-keyword">of</span> processed code. 
This error may be caused by a breaking change <span class="hljs-keyword">in</span> Jest <span class="hljs-number">28</span>: https:<span class="hljs-comment">//jestjs.io/docs/upgrading-to-jest28#transformer Code Transformation Documentation: https://jestjs.io/docs/code-transformation</span>
</code></pre><p>This is because the <code>process()</code> functions that used to return a string now expect an object in the format of <code>{ code:</code>old_string_here<code>}</code>. </p>
<p>To fix this, we go into our ejected <code>config/jest</code> folder, and we change the output shape for all our files. For CSS, it's a single line change:</p>
<pre><code class="lang-js"><span class="hljs-comment">// This is a custom Jest transformer turning style imports into empty objects. </span>
<span class="hljs-comment">// http://facebook.github.io/jest/docs/en/webpack.html </span>

<span class="hljs-built_in">module</span>.exports = { 
    process() { 
        <span class="hljs-keyword">return</span> { <span class="hljs-attr">code</span>: <span class="hljs-string">'module.exports = {};'</span> }; 
    }, 
    getCacheKey() { 
        <span class="hljs-comment">// The output is always the same. </span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">'cssTransform'</span>; 
    }, 
};
</code></pre>
<p>and for files, you have to change both branch return statements:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'path'</span>); 
<span class="hljs-keyword">const</span> camelcase = <span class="hljs-built_in">require</span>(<span class="hljs-string">'camelcase'</span>); 

<span class="hljs-comment">// This is a custom Jest transformer turning file imports into filenames. // http://facebook.github.io/jest/docs/en/webpack.html </span>
<span class="hljs-built_in">module</span>.exports = { 
    process(src, filename) { 
        <span class="hljs-keyword">const</span> assetFilename = <span class="hljs-built_in">JSON</span>.stringify(path.basename(filename)); 
        <span class="hljs-keyword">if</span> (filename.match(<span class="hljs-regexp">/\.svg$/</span>)) { 
            <span class="hljs-comment">// Based on how SVGR generates a component name: </span>
            <span class="hljs-comment">// https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6 </span>
            <span class="hljs-keyword">const</span> pascalCaseFilename = camelcase(path.parse(filename).name, { <span class="hljs-attr">pascalCase</span>: <span class="hljs-literal">true</span>, }); 
            <span class="hljs-keyword">const</span> componentName = <span class="hljs-string">`Svg<span class="hljs-subst">${pascalCaseFilename}</span>`</span>; 
            <span class="hljs-keyword">return</span> { <span class="hljs-attr">code</span>: <span class="hljs-string">`const React = require('react')...`</span> <span class="hljs-comment">// pretty long string }; </span>
        }

        <span class="hljs-keyword">return</span> {<span class="hljs-attr">code</span>: <span class="hljs-string">`module.exports = <span class="hljs-subst">${assetFilename}</span>;`</span> }; 
    }, 
};
</code></pre>
<p>Note: As of the time of writing, the error message link to the upgrade guide tutorial <a target="_blank" href="https://github.com/jestjs/jest/issues/15112#issuecomment-2160883936">doesn't work</a>, but you can find the correct link at <a target="_blank" href="https://jest-archive-august-2023.netlify.app/docs/28.x/upgrading-to-jest28/">https://jest-archive-august-2023.netlify.app/docs/28.x/upgrading-to-jest28/</a>. There's also an older <a target="_blank" href="https://web.archive.org/web/20230330085721/https://jestjs.io/docs/28.x/upgrading-to-jest28#transformer">archive link</a> if that doesn't work.</p>
<h3 id="heading-how-to-bump-jest-to-29">How to Bump Jest to 29</h3>
<p>Once all the validation steps are working with Jest 28, the upgrade to 29 should be smoother. Just update your <code>package.json</code> and run <code>$ yarn install</code>:</p>
<pre><code class="lang-json">... 
<span class="hljs-string">"devDependencies"</span>: { ... 
    <span class="hljs-attr">"babel-jest"</span>: <span class="hljs-string">"^29.7.0"</span>, 
    <span class="hljs-attr">"jest"</span>: <span class="hljs-string">"^29.7.0"</span>, 
    <span class="hljs-attr">"jest-circus"</span>: <span class="hljs-string">"^29.7.0"</span>, 
    <span class="hljs-attr">"jest-resolve"</span>: <span class="hljs-string">"^29.7.0"</span>, 
    <span class="hljs-attr">"jest-environment-jsdom"</span>: <span class="hljs-string">"^29.7.0"</span> ... 
} 
...
</code></pre>
<p>At this point, <code>$ yarn test</code> should work correctly with your existing test suite. </p>
<h2 id="heading-how-far-should-i-upgrade-nodejs">How Far Should I Upgrade NodeJS?</h2>
<p>Trying to decide how far ahead to upgrade Node versions can be a tricky question. Following the above steps, I was able to get all the Node versions up until the most recent Node 22 working. </p>
<p>At the time of writing, 18 is a pretty good stopping point in terms of current support and recent ECMAScript support. But if you're looking to decide, then the following three factors are the most important:</p>
<ol>
<li>Library support: Look at all your critical libraries and see if they have a strong preference for a certain version or have breaking issues for more recent versions. Later Node versions are usually better, but sometimes old libraries didn't get the right patches and might block your upgrade.</li>
<li>Support windows: Different Node versions have a window where the maintainers consider it under "Maintenance", "Active", "Current" or "Unsupported", and over time the older versions lose maintenance. The even versions are also designated LTS (Long Term Support), giving support for a long time and what works for most people. The website has a helpful chart for this: <a target="_blank" href="https://nodejs.org/en/about/previous-releases">https://nodejs.org/en/about/previous-releases</a>.</li>
<li>Language feature support: ECMAScript's specification is always evolving with every year, and getting to use the newer syntax with nicer constructs is always a big quality of life upgrade. I love <a target="_blank" href="https://node.green/">https://node.green/</a> which has a table of Node versions against ECMAScript syntax features with code examples for each feature.</li>
</ol>
<p>Due to technologies like <a target="_blank" href="https://babeljs.io/">Babel</a> (bundled with Create React App), you don't need to worry too much about the end users of your website, as newer Node features will just get transpiled to browser-compliant ones.</p>
<h2 id="heading-should-you-still-use-create-react-scripts-what-alternatives-are-there">Should You Still Use Create React Scripts? What Alternatives Are There?</h2>
<p>In this tutorial, I decided to eject out of CRA to access the Webpack and Babel configuration, and many CRA projects have eventually come to do this as well. Maintenance of CRA has nearly stopped while the ecosystem keeps evolving. </p>
<p>Personally, I recommend someone creating a React project today to try newer alternatives like <a target="_blank" href="https://vitejs.dev/guide/">Vite</a> or <a target="_blank" href="https://parceljs.org/recipes/react/">Parcel</a> which have a nice starter applications that are simple and easier to understand. Unfortunately, they might not have as many bells and whistles as what CRA gives, but it's good enough for almost all practical modern development. </p>
<p>In the context of education, my old tutorials used <code>create-react-app</code>, and it was such a major help, but my newer ones will use Vite.</p>
<p>Still, your application and development experience might be very different than mine. I recommend reading and learning from these resources to form your own perspective:</p>
<ul>
<li>GitHub <a target="_blank" href="https://github.com/reactjs/react.dev/pull/5487">issue</a> with 200+ responses and 1000s of reactions on if Create React App should be replaced with Vite on the official docs. It also has a <a target="_blank" href="https://github.com/reactjs/react.dev/pull/5487#issuecomment-1409720741">note</a> from the maintainer side of CRA explaining a lot of important context that is highly worth reading. Parcel's maintainer made a really good <a target="_blank" href="https://github.com/reactjs/react.dev/pull/5487#issuecomment-1399360209">comment</a> as well.</li>
<li>Some interesting comments (<a target="_blank" href="https://github.com/reactjs/react.dev/pull/5487#issuecomment-1423368130">one</a>, <a target="_blank" href="https://github.com/facebook/create-react-app/issues/13598">two</a>) on how CRA created a simple and easy to use React experience out of the box without worrying about setup hell and focusing on the actual application.</li>
<li><a target="_blank" href="https://medium.com/@vivekdwivedi/the-end-of-an-era-react-team-no-longer-recommends-create-react-app-f2fe6e842d13">News article</a> explaining that the React Team has chosen to stop recommending Create React App, along with some context behind this and future alternatives.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>At this point, you should be able to run all your validation scripts and have an application that works with Node 18+ and Jest 29+.</p>
<p>In an ideal world, you'd run into the same hurdles as I did, and everything would be working. Realistically, everyone's application is different, and the internet is full of numerous developers who have gone through this upgrade process with various issues. </p>
<p>I highly suggest making Google, StackOverflow, GitHub, and official library documentation your best friends in the process, and I wish you good luck!</p>
<h3 id="heading-alternatively-how-to-upgrade-to-react-scripts-501">Alternatively: How to Upgrade to React Scripts 5.0.1</h3>
<p>This is beyond the scope of this tutorial, so I'll be briefer here – but here's a little information to get you started. </p>
<p>I suggest starting with the official docs changelog for CRA v5 that includes all the major changes as well as some version upgrade instructions: <a target="_blank" href="https://github.com/facebook/create-react-app/blob/main/CHANGELOG.md">https://github.com/facebook/create-react-app/blob/main/CHANGELOG.md</a>.</p>
<p>Bumping the version is fairly easy, setting <code>react-scripts</code> to <code>5.0.1</code> in your <code>package.json</code>, but then the hard part is all the breaking changes.</p>
<p>The most complicated part of the upgrade is the upgrade to Webpack 5 from Webpack 4. Read Webpack's official guide <a target="_blank" href="https://webpack.js.org/migrate/5/">To v5 from v4</a> which has a nice overview, and look around the internet for guides for this upgrade. A few more hurdles that you might come across:</p>
<ul>
<li>For <code>@babel/helper-compilation-targets: 'opera_mobile' is not a valid target</code> you can add <code>"not op_mob &gt;= 1"</code> to the <code>browserslist</code> array as suggested by this <a target="_blank" href="https://github.com/babel/babel/issues/16171#issuecomment-2015227043">comment</a> on the babel issue tracker. The other comments may also be helpful.</li>
<li>You'll probably have to access the CRA internals for many steps using either React Scripts <code>eject</code> or something like <a target="_blank" href="https://craco.js.org/docs/getting-started/">CRACO version 7</a>.</li>
<li>Webpack 5 has a breaking change which removes support for a lot of browser specific APIs like <code>os</code>, <code>http</code>, <code>util</code> that worked in Webpack 4 that your application may have been using. You can either add all of them back using a package like <a target="_blank" href="https://github.com/Richienb/node-polyfill-webpack-plugin">node-polyfill-webpack-plugin</a> or add imports piecewise following this <a target="_blank" href="https://gist.github.com/ef4/d2cf5672a93cf241fd47c020b9b3066a">cheatsheet</a>.</li>
<li>For Babel eslint parser load errors like <code>Error: Failed to load parser 'babel-eslint' declared in '.eslintrc': Cannot find module 'babel-eslint'</code> , you might have to swap out <code>"parser": "babel-eslint"</code> with <code>"parser": "@babel/eslint-parser"</code> in your <code>.eslintrc</code> and install <code>"@babel/eslint-parser"</code> in your <code>package.json</code>. This might be caused by the move of <code>babel-eslint</code> to the <code>@babel</code> monorepo, see <a target="_blank" href="https://babeljs.io/blog/2020/07/13/the-state-of-babel-eslint">The State of babel-eslint</a> for more info.</li>
<li>Some filetype imports that used to work with Webpack 4 will start breaking with <code>Module build failed: UnhandledSchemeError</code> (the actual error took several screens in my Terminal). The solution here will be fixing the prefixes of the files you import, and for external files that were being included, see if you can find a npm package for it. For example, one of my projects stopped using <code>semantic-ui.min.css</code> downloaded from the internet, and instead I added <code>"semantic-ui-css": "^2.5.0"</code> to my <code>package.json</code>. Definitely read this <a target="_blank" href="https://github.com/webpack/webpack/issues/12792">issue</a> thread in the webpack repo for more information.</li>
</ul>
<p>After all of these I was able to get <code>yarn test</code> and <code>yarn build</code> to succeed, but <code>yarn start</code> still had too many issues and I pivoted to making CRA v4 work instead. Hopefully you might get further than I did.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Counter Button with React, TailwindCSS, and TypeScript ]]>
                </title>
                <description>
                    <![CDATA[ How can you keep track of the number of times a user clicks a button? How are the hearts on Instagram or the likes on Facebook counted?  In this tutorial, we will build a button that tracks the number of times a button has been clicked. Along the way... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-counter-button-with-react/</link>
                <guid isPermaLink="false">66bce123d84f19f03de63fd1</guid>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tailwind ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Devin Lane ]]>
                </dc:creator>
                <pubDate>Wed, 10 Jul 2024 14:41:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/Build-a-counter-button-with-React-6-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>How can you keep track of the number of times a user clicks a button? How are the hearts on Instagram or the likes on Facebook counted? </p>
<p>In this tutorial, we will build a button that tracks the number of times a button has been clicked. Along the way, you will learn some fundamental concepts in React such as components, JSX, passing props between components, and managing state with hooks. You will also get small introductions to Tailwind and TypeScript.</p>
<p>This tutorial builds upon examples and concepts outlined in the "Learn" section of the React documentation, which you can find <a target="_blank" href="https://react.dev/learn">here</a>.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>Basic familiarity with JavaScript, such as working with variables, functions, arrays, and objects. </li>
<li>Basic familiarity with CSS and HTML.</li>
<li>Basic familiarity with the command line.</li>
<li><a target="_blank" href="https://nodejs.org/en">Node</a> installed.</li>
<li>A code editor of your choice (I'll be using <a target="_blank" href="https://code.visualstudio.com/">Visual Studio Code</a> here)</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-chapter-1-how-to-build-the-counter-button">How to Build the Counter Button</a></li>
<li><a class="post-section-overview" href="#heading-chapter-2-how-to-refactor-the-project">How to Refactor the Project</a></li>
<li><a class="post-section-overview" href="#heading-chapter-3-two-components-with-independent-and-shared-state">Two Components with Independent and Shared State</a></li>
<li><a class="post-section-overview" href="#heading-chapter-4-how-to-add-both-pairs-of-buttons-to-our-site">How to Add Both Pairs of Buttons to our Website</a></li>
<li><a class="post-section-overview" href="#heading-chapter-5-how-to-deploy-the-site-to-netlify">How to Deploy the Site to Netlify</a></li>
</ol>
<h2 id="heading-chapter-1-how-to-build-the-counter-button">Chapter 1: How to Build the Counter Button</h2>
<h3 id="heading-what-is-react">What is React?</h3>
<p>Before we dive in, let's define React. <a target="_blank" href="https://react.dev/">React</a> is a JavaScript library for creating user interfaces out of pieces called <em>components</em>. Components are JavaScript functions that can receive and display data interactively to your users.</p>
<h3 id="heading-project-setup">Project setup</h3>
<p>We're going to use <a target="_blank" href="https://nextjs.org/">Next.js</a> for our local React setup.</p>
<p>Within the directory you'd like to store this project, open your terminal and execute the following command:</p>
<pre><code class="lang-zsh">npx create-next-app@latest
</code></pre>
<p>Name your project however you like, and answer the commands as follows:</p>
<pre><code class="lang-zsh">What is your project named? react-counter-button
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 to use `src/` directory? No
Would you like to use App Router? (recommended) Yes
Would you like to customize the default import <span class="hljs-built_in">alias</span> (@/*)? No
</code></pre>
<p>Now let's <code>cd</code> into our project directory</p>
<pre><code class="lang-zsh"><span class="hljs-built_in">cd</span> react-counter-button
</code></pre>
<p>And run the project in Visual Studio Code:</p>
<pre><code class="lang-zsh">code .
</code></pre>
<p>Note: if you don't have the <code>code</code> command in your PATH, you can press ⇧⌘P (Ctrl+Shift+P on Windows/Linux) and type in 'Shell Command: Install 'code' command in PATH'. Alternatively, you can drag the folder onto the Visual Studio Code icon in MacOS. Or, within Visual Studio Code, you can select File -&gt; Open, and find "react-counter-button", or the name of your project. </p>
<p>In your terminal run:</p>
<pre><code class="lang-zsh">npm run dev
</code></pre>
<p>Open your browser to <code>localhost:3000</code> and you should see the following page:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-14-at-7.10.35-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Next.js boilerplate</em></p>
<p>We now have the project up and running. Back over in our code editor, we can begin the work.</p>
<h3 id="heading-remove-boilerplate">Remove boilerplate</h3>
<p>In <code>app/page.tsx</code>, let's delete most of the boilerplate code except the two <code>main</code> tags. Then let's add a title for our project in an <code>h1</code> tag in between the <code>main</code> tags. Our code should look like this:</p>
<pre><code class="lang-js"><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">"flex min-h-screen flex-col items-center justify-between p-24"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>React Counter Button<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
    );
}
</code></pre>
<p>Here's what we should now see:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-16-at-8.22.30-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Initial state of our project</em></p>
<h3 id="heading-writing-our-first-component">Writing our first component</h3>
<p>Let's create our first component. A React component is a function that returns markup. Below and outside of the scope of our <code>Home</code> function, let's write the following:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</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">button</span>&gt;</span>I have been clicked X times<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
}
</code></pre>
<p>Here we have a function <code>Button</code> that returns some markup in JSX. JSX looks a lot like HTML, but it can display dynamic content, and has stricter rules than HTML. You can learn more about JSX in the React docs <a target="_blank" href="https://react.dev/learn/writing-markup-with-jsx">here</a>.</p>
<p>The <code>Button</code> function must be uppercase to be recognized as a valid React component. This contrasts it with an HTML tag, which is lower case.</p>
<p>You'll notice that we still see no change on our webpage – we need to render this component in order to see it on the screen. </p>
<p>We can use our <code>Button</code> component as if it were an HTML tag we created. If we nest the <code>Button</code> component within the <code>Home</code> component, we should see it on the screen:</p>
<pre><code class="lang-js"><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">"flex min-h-screen flex-col items-center justify-between p-24"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>React Counter Button<span class="hljs-tag">&lt;/<span class="hljs-name">h1</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">main</span>&gt;</span></span>
    );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</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">button</span>&gt;</span>I have been clicked X times<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>;
}
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-at-6.37.57-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Rendering the <code>Button</code> component (with less than ideal CSS)</em></p>
<h3 id="heading-styling-our-first-component-with-tailwind">Styling our first component with Tailwind</h3>
<p>You'll notice the button is on the bottom of the screen. This is because the styles on <code>main</code> include <code>justify-between</code> in the <code>flex-col</code> direction. If we remove <code>justify-between</code> we should see this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-at-6.36.57-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Improving the CSS of the initial state of our application</em></p>
<p>You can read more about aligning items in a flexbox from MDN <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Aligning_Items_in_a_Flex_Container">here</a>.</p>
<p>You'll also notice that the button is un-styled. This is because <a target="_blank" href="https://tailwindcss.com/">Tailwind</a> removes default styling on buttons as a part of their "preflight" styles. If you're curious to see where these styles come from, you can open <code>node_modules/tailwindcss/src/css/preflight.css</code> and check out ~line 193 (permalink on GitHub <a target="_blank" href="https://github.com/tailwindlabs/tailwindcss/blob/332347ed834a3078547923ccfddc1c22035011b6/packages/tailwindcss/preflight.css#L182">here</a>):</p>
<pre><code class="lang-css"><span class="hljs-comment">/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/</span>

<span class="hljs-selector-tag">button</span>,
<span class="hljs-selector-attr">[type=<span class="hljs-string">'button'</span>]</span>,
<span class="hljs-selector-attr">[type=<span class="hljs-string">'reset'</span>]</span>,
<span class="hljs-selector-attr">[type=<span class="hljs-string">'submit'</span>]</span> {
  <span class="hljs-attribute">-webkit-appearance</span>: button; <span class="hljs-comment">/* 1 */</span>
  <span class="hljs-attribute">background-color</span>: transparent; <span class="hljs-comment">/* 2 */</span>
  <span class="hljs-attribute">background-image</span>: none; <span class="hljs-comment">/* 2 */</span>
}
</code></pre>
<p>We're not going to change the styles within <code>node_modules</code> – instead we'll add our own styling to the Button component. One of the benefits of Tailwind is that our CSS is co-located with our JavaScript, making quick changes to styles easier than opening a separate stylesheet file. </p>
<p>Let's make the following changes:</p>
<pre><code class="lang-js"><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">"flex min-h-screen flex-col items-center p-24 gap-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>React Counter Button<span class="hljs-tag">&lt;/<span class="hljs-name">h1</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">main</span>&gt;</span></span>
    );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</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">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 rounded text-white font-bold px-4 py-2"</span>&gt;</span>
            I have been clicked X times
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
}
</code></pre>
<p>We've added styles to our button, and we've also added a <code>gap-4</code> to our <code>main</code> parent flex box to provide a space between the <code>h1</code> and the <code>button</code>. (You can read more about the CSS property "gap" in the MDN <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/gap">here</a>.) We should now see this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/10/Screenshot-2023-10-20-at-6.49.22-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Viewing our styled <code>Button</code> component</em></p>
<h3 id="heading-wait-but-what-is-tailwind">Wait, but what is Tailwind?</h3>
<p>Now that we've styled our button component and spaced the items out, let's reflect on what Tailwind is, and what it provided for us. <a target="_blank" href="https://tailwindcss.com/">Tailwind</a> is a CSS framework that provides a set of "utility" classes that we can use to style each element. </p>
<p>But what is a utility class? You'll see that to style our button, we added classes such as <code>bg-blue-500</code> – which corresponds to setting the CSS <code>background-color</code> property to blue, and <code>rounded</code> – which corresponds to <code>border-radius: 0.25rem</code>. </p>
<p>Each class is defined according to its <em>utility:</em> changing the background color, the border radius, and so on. Through adding these utility classes to our elements, we arrive at our desired styles. </p>
<p>Tailwind sits in contrast to other frameworks, such as Bootstrap, that provide predefined classes for elements such as buttons. In Bootstrap, we would add a class of <code>btn</code> to achieve a styled button. And of course, with standard CSS we would likely add a custom class (perhaps called <code>button</code>) to our element and create CSS rulesets in a separate stylesheet. </p>
<p>Returning to our project, so far we've set up a React project using Next.js, created our first React component, and styled our button using Tailwind. How do we introduce the counter functionality?</p>
<h3 id="heading-how-to-add-state">How to add state</h3>
<p>In order to display the number of times a button has been clicked, we need to use an event handler, and we need a way to manage <em>state.</em> </p>
<p><a target="_blank" href="https://react.dev/learn/state-a-components-memory">State</a> is component-specific memory. In our example, this is how the button will remember how many times it has been clicked. Using a special React function "<a target="_blank" href="https://react.dev/reference/react/hooks">hook</a>", we trigger a re-render and retain the data across renders – the <code>[useState](https://react.dev/reference/react/useState)</code> hook is provided by React for this purpose. </p>
<p>At the top of our <code>page.tsx</code>, let's import <code>useState</code>: </p>
<p><code>import { useState } from "react"</code></p>
<p>and within our <code>Button</code> component, let's add the following:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</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">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 rounded py-2 px-4 text-white font-bold"</span>&gt;</span>
            I have been clicked X times
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
}
</code></pre>
<p>Let's unpack what we have here: </p>
<ul>
<li>We're using the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">destructuring assignment</a> to get the values of <code>count</code> and the function <code>setCount</code> from <code>useState</code>. The convention is to name these two values <code>something</code> and <code>setSomething</code>, though we could name them anything. </li>
<li>The argument to <code>useState</code> is the initial value of our state variable. Here we've set it to 0.</li>
<li><code>count</code> is our current state.</li>
<li><code>setCount</code> is the function that updates our state and triggers a re-render. </li>
</ul>
<p>However, if you click save you'll see the following error in your terminal and in your browser:</p>
<pre><code class="lang-zsh">You<span class="hljs-string">'re importing a component that needs useState. It only works in a Client Component but none of its parents are marked with "use client", so they'</span>re Server Components by default.
Learn more: https://nextjs.org/docs/getting-started/react-essentials

   ╭─[/[...your project path]/src/app/page.tsx:1:1]
 1 │ import { useState } from <span class="hljs-string">"react"</span>;
   ·          ────────
 2 │ 
 3 │ <span class="hljs-built_in">export</span> default <span class="hljs-keyword">function</span> <span class="hljs-function"><span class="hljs-title">Home</span></span>() {
 4 │     <span class="hljs-built_in">return</span> (
   ╰────

Maybe one of these should be marked as a client entry with <span class="hljs-string">"use client"</span>:
  ./src/app/page.tsx
</code></pre>
<p>This is due to Next.js's use of <a target="_blank" href="https://www.joshwcomeau.com/react/server-components/">React Server Components</a>, which you can learn more about <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/rendering">here</a>. React Server Components is a large topic, but the bottom line is that, by default, components are Server Components in Next.js and <code>useState</code> only works in a Client Component. If we write the  <code>"use client"</code> directive at the top of our <code>page.tsx</code>, we resolve the error.</p>
<h3 id="heading-how-to-evaluate-javascript-within-jsx">How to Evaluate JavaScript within JSX</h3>
<p>If we click the button, we still don't see the numbers update. This is because we need a way to <em><a target="_blank" href="https://react.dev/learn/javascript-in-jsx-with-curly-braces">interpolate</a></em> (or evaluate) JavaScript within our JSX markup. Enter the curly braces: <code>{}</code>.</p>
<p>We can use curly braces to "escape" into JavaScript from within JSX markup. This way we can evaluate JavaScript expressions (such as adding to a counter) and dynamically display data in our components. Here's what we'll do:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyButton</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</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">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 rounded py-2 px-4 text-white font-bold"</span>&gt;</span>
            I have been clicked {count} times
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
}
</code></pre>
<p>We have added <code>{count}</code> to evaluate the value of <code>count</code> from <code>useState</code> within our button. We should see the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Screenshot-2023-11-26-at-4.46.56-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Displaying data in JSX with curly braces {}</em></p>
<p>We see a 0 – this comes from the <code>count</code> variable that we destructured from our <code>useState</code> hook, which we initially set to 0. We've successfully interpolated the JavaScript within our JSX markup!</p>
<h3 id="heading-event-handling">Event handling</h3>
<p>You'll notice that if we click the button, still nothing happens. How do we get the number to increment when we click it? </p>
<p>For this, we'll make use of an <a target="_blank" href="https://react.dev/learn/responding-to-events#adding-event-handlers">event handler function</a> as well as the setter function (which we named <code>setCount</code>) that we get from <code>useState</code>:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyButton</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params"></span>) </span>{
        setCount(count + <span class="hljs-number">1</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">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 rounded py-2 px-4 text-white font-bold"</span>&gt;</span>
            I have been clicked {count} times
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
}
</code></pre>
<p>What we've done here is add a function <code>handleClick</code> to update the state of the <code>count</code> variable. The convention is to name event handler functions <code>handle</code> followed by the name of your event (for example, <code>handleClick</code>). </p>
<p><code>[setCount](https://react.dev/reference/react/useState#setstate)</code> is a special <code>set</code> function returned by <code>useState</code> that will update the state of the <code>count</code> variable to whatever we pass in as an argument. For example, we could call <code>setCount(2)</code>, and it would update <code>count</code> to 2. <code>setCount(7)</code> would set it to 7, and so on. </p>
<p>We are calling <code>setCount(count + 1)</code>, which evaluates to <code>setCount(0 + 1)</code>, because the initial value of <code>count</code> is 0. Upon the next click, <code>count</code> will be 1, so we'd be calling <code>setCount(1 + 1)</code>, and the next click would call <code>setCount(2 + 1)</code> and so on. </p>
<p>This allows us to update the counter with every click. But, if you click, you'll notice that <em>still</em> nothing happens – why? Perhaps take a moment to try to figure this out for yourself before reading on to help the concept stick even better.</p>
<h3 id="heading-how-to-pass-an-event-handler-as-a-prop-to-your-jsx">How to Pass an Event Handler as a Prop to Your JSX</h3>
<p>Looking at our code, there is no relationship between the user clicking the button, and the <code>handleClick</code> function. We need to pass the <code>handleClick</code> event handler to the <code>onClick</code> property on the button! Let's add that here:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyButton</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params"></span>) </span>{
        setCount(count + <span class="hljs-number">1</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">onClick</span>=<span class="hljs-string">{handleClick}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 rounded py-2 px-4 text-white font-bold"</span>
        &gt;</span>
            I have been clicked {count} times
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
}
</code></pre>
<p>Notice how we haven't said <code>onClick={handleClick()}</code>. We aren't calling the function ourselves here – we are instead passing it down. This is an important distinction, as React calls the function for us when the user clicks the button, instead of it firing immediately. </p>
<p>You can learn more about passing props to components in the React docs <a target="_blank" href="https://react.dev/learn/passing-props-to-a-component">here</a>.</p>
<h3 id="heading-our-working-project">Our working project</h3>
<p>Try it out now, the button works! </p>
<p>You now have a button that updates its count when you click it. This shows usage of interpolating JavaScript within JSX using curly braces, creating your own component and nesting it within other components, using state and hooks within React, as well as working with Next.js and Tailwind. Congratulations! </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/react-counter-button.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Our working project</em></p>
<p>Here would be a good point to <em>commit</em> our changes using Git. You can close the current terminal process by pressing <code>ctrl + c</code>, and then type in <code>git add .</code>, followed by <code>git commit -m "counter button"</code> or some other message that is meaningful.</p>
<h2 id="heading-chapter-2-how-to-refactor-the-project">Chapter 2: How to Refactor the Project</h2>
<h3 id="heading-moving-our-component-to-another-file">Moving our component to another file</h3>
<p>As our project sits, all the code is within <code>app/page.tsx</code>. What if we wanted to add another component, or several? Over time, our <code>page.tsx</code> would get large and difficult to read. </p>
<p>Instead, we can break our components up into their own files to help with readability as well as modularity (reusing the component in multiple different places).</p>
<p>Let's start by creating a folder <code>components</code> at the root of our project to store our components. Inside <code>components</code>, create a file called <code>button.tsx</code>. Then, within <code>app/page.tsx</code> cut (copy and then delete) the entire <code>Button</code> function component and paste it within <code>components/button.tsx</code>. </p>
<p><code>components/button.tsx</code> should look like this:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Button</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params"></span>) </span>{
        setCount(count + <span class="hljs-number">1</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">onClick</span>=<span class="hljs-string">{handleClick}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 rounded text-white font-bold px-4 py-2"</span>
        &gt;</span>
            I have been clicked {count} times
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
}
</code></pre>
<h3 id="heading-fix-the-usestate-import-error">Fix the <code>useState</code> import error</h3>
<p>You'll likely notice in your code editor that <code>useState(0)</code> has red squiggly lines underneath it. In Visual Studio Code, if you hover over it, you will see an error that says:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-06-07-at-6.10.44-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Error: cannot find name 'useState'</em></p>
<p>Why is this? We are using <code>useState</code> but we have not imported the module from React. Adding <code>import { useState } from "react";</code> to the top of our <code>button.tsx</code> file will fix this error.</p>
<p>If you look at the beginning of the function, you'll see that <code>Button()</code> is underlined with white lines in Visual Studio Code. Hovering over it will show this error. Reflect on why this might be the case – we'll address this later. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-06-07-at-6.13.45-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Error: 'Button' is declared but its value is never read</em></p>
<h3 id="heading-importing-and-exporting-components">Importing and Exporting Components</h3>
<p>Let's return to <code>app/page.tsx</code> . You'll see two errors here: one on <code>import { useState } from "react";</code> and another on <code>&lt;Button /&gt;</code>. </p>
<p>Let's address the <code>useState</code> error first. We used <code>useState</code> within our <code>Button</code> component, but now that we've moved that component to its own file, we no longer it. Deleting it will solve our error. You can use <code>cmd (ctrl on Windows) + shift + k</code> to delete the entire line in Visual Studio Code.</p>
<p>If you've saved your <code>app/page.tsx</code> you will see this error in the console:</p>
<pre><code class="lang-zsh"> ⨯ app/page.tsx (7:14) @ Button
 ⨯ ReferenceError: Button is not defined
    at Home (./app/page.tsx:19:89)
digest: <span class="hljs-string">"2129895745"</span>
   5 |         &lt;main className=<span class="hljs-string">"flex min-h-screen flex-col items-center p-24 gap-4"</span>&gt;
   6 |             &lt;h1&gt;React Counter Button&lt;/h1&gt;
&gt;  7 |             &lt;Button /&gt;
     |              ^
   8 |         &lt;/main&gt;
   9 |     );
  10 | }
 GET / 500 <span class="hljs-keyword">in</span> 87ms
</code></pre>
<p>Why wouldn't <code>Button</code> be defined? The issue is that within our <code>app/page.tsx</code> we have no way to access the <code>Button</code> component over in <code>components/button.tsx</code>. We solve this by exporting and importing the appropriate module.</p>
<p>Within <code>components/button.tsx</code>, at the beginning of our function declaration, let's add the keywords <code>export default</code>. The file will look like this now:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { useState } <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">Button</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params"></span>) </span>{
        setCount(count + <span class="hljs-number">1</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">onClick</span>=<span class="hljs-string">{handleClick}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 rounded text-white font-bold px-4 py-2"</span>
        &gt;</span>
            I have been clicked {count} times
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
}
</code></pre>
<p>You'll notice that our earlier error of <code>'Button' is declared but its value is never read</code> has gone away, because now the value is being read as a default export. </p>
<p>But what have we done here? What is an export, or a default export? <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export">Exporting</a> and importing allows us to modularize JavaScript components into their own sections and use them in others. </p>
<p>There are two types: <em>default</em> exports<em>,</em> and <em>named</em> exports. Each file can have multiple <em>named</em> exports but only one <em>default</em> export. You can read more about importing and exporting components the React documentation <a target="_blank" href="https://react.dev/learn/importing-and-exporting-components">here</a>.</p>
<p>Now that we have exported the component from <code>components/button.tsx</code>, we have to import it within <code>app/page.tsx</code>. Visual Studio Code can help with "<a target="_blank" href="https://code.visualstudio.com/docs/editor/intellisense">intellisense</a>" suggestions: at the top of your file if you start typing "Button", it will suggest the correct import with the correct filepath:</p>
<p><code>import Button from "@/components/button";</code></p>
<p>Within Next.js we can use this <code>@/</code> syntax to reference the root of the project. This is a convenience added in case our import is several file layers deep. You can read the examples of the <code>@/</code> syntax in the Next.js documentation <a target="_blank" href="https://nextjs.org/docs/app/building-your-application/configuring/absolute-imports-and-module-aliases">here</a>. </p>
<p>You'll see that our errors have disappeared and the project still works! We haven't added any new features but we have successfully refactored our code to make it more modular, readable, and maintainable.</p>
<p>Here let's follow the same steps to commit our changes, adding a message such as <code>refactor: move button to its own file</code>.</p>
<h2 id="heading-chapter-3-two-components-with-independent-and-shared-state">Chapter 3: Two Components with Independent and Shared State</h2>
<h3 id="heading-two-components-with-independent-state">Two Components with Independent State</h3>
<p>What if we wanted to have two buttons that can count independently of each other? This will showcase the beauty of React and component-based development implementation will be simpler than building the button from scratch entirely again.</p>
<p>Within <code>app/page.tsx</code> we can simply add another <code>&lt;Button /&gt;</code>. You can focus your cursor on <code>&lt;Button /&gt;</code> and press <code>option + shift + ↓</code> to create another <code>&lt;Button /&gt;</code>:</p>
<pre><code class="lang-js"><span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/button"</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">"flex min-h-screen flex-col items-center p-24 gap-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>React Counter Button<span class="hljs-tag">&lt;/<span class="hljs-name">h1</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">Button</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
    );
}
</code></pre>
<p>You should now see two button counters with their own independent state:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-06-07-at-6.40.47-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Two buttons with independent state</em></p>
<p>Component-based design with React makes re-using parts of your application easy. Easy win.</p>
<h3 id="heading-two-components-with-shared-state">Two Components with Shared State</h3>
<p>What if we wanted the buttons to share their state and update together? You'll notice that as we click each button, they separately increment. </p>
<p>In order for the buttons to share their state, we will need to move their state from each individual components "upward" to their common parent component (in this case, the <code>Home</code> function in <code>app/page.tsx</code>). You'll also hear this referred to as "<a target="_blank" href="https://react.dev/learn#sharing-data-between-components">lifting state up</a><em>".</em></p>
<p>Cut the counting logic from <code>components/button.tsx</code> and paste it into <code>app/page.tsx</code> within the body of the <code>Home</code> function. We will also need our <code>useState</code> import at the top of the file:</p>
<pre><code class="lang-js"><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> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/button"</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">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params"></span>) </span>{
        setCount(count + <span class="hljs-number">1</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">"flex min-h-screen flex-col items-center p-24 gap-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>React Counter Button<span class="hljs-tag">&lt;/<span class="hljs-name">h1</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">Button</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
    );
}
</code></pre>
<h3 id="heading-passing-props-down-to-a-component">Passing Props Down to a Component</h3>
<p>Now that we have our state in the parent component of each button (<code>Home</code>), we can pass this state down via <em><a target="_blank" href="https://react.dev/learn/passing-props-to-a-component">props</a></em> to the <code>Button</code> component. We will want to pass down both the event handler <code>handleClick</code> as well as the <code>count</code> variable we wish to display:</p>
<pre><code class="lang-js"><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> Button <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/button"</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">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params"></span>) </span>{
        setCount(count + <span class="hljs-number">1</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">"flex min-h-screen flex-col items-center p-24 gap-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>React Counter Button<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">count</span>=<span class="hljs-string">{count}</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">count</span>=<span class="hljs-string">{count}</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
    );
}
</code></pre>
<p>The <code>count</code> from <code>useState</code> is passed to the <code>count</code> prop, and the function <code>handleClick</code> is passed to the <code>onClick</code> prop, both on the <code>Button</code> component. In JSX, we can define our own props (which might remind you of HTML attributes) so that we can pass data from one component to another. </p>
<p>You might see some errors related to TypeScript at this point – we will come back to these later.</p>
<h3 id="heading-read-props-in-your-child-component">Read Props in Your Child Component</h3>
<p>Now that we have passed the data as props to our component, we need to adjust our <code>Button</code> component to <em>read</em> the props from its parent component. Within <code>components/button.tsx</code>:</p>
<pre><code class="lang-js"><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">Button</span>(<span class="hljs-params">{ count, onClick }</span>) </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">onClick</span>=<span class="hljs-string">{onClick}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 rounded text-white font-bold px-4 py-2"</span>
        &gt;</span>
            I have been clicked {count} times
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
}
</code></pre>
<p>React function components accept a single <code>props</code> object as an argument. Here we destructure the props that we want to pass into our <code>Button</code> component. In other words, we are taking <code>count</code>, and <code>onClick</code> from the <code>props</code> object directly, as an argument to <code>Button</code>.</p>
<p>If you save your file you'll see that this now works: you have two buttons with shared state:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screen-Recording-2024-06-14-at-12.07.37-PM.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Two buttons with shared state</em></p>
<p>But why did we pass <code>onClick</code> and not <code>handleClick</code> to the <code>Button</code> component? Isn't <code>handleClick</code> what we want to run when we click the button?</p>
<p>Within the <code>Home</code> component in <code>app/page.tsx</code>, we define <code>handleClick</code> and pass it down as a prop to the <code>Button</code> component. Within the <code>Button</code> component's body in <code>components/button.tsx</code> we read the <em>prop</em> <code>onClick</code>, not the event handler <code>handleClick</code> itself. So when the <code>Button</code> component fires, it calls the <code>onClick</code> prop, which sits "up" the component tree inside <code>Home</code>, where it then calls <code>handleClick</code>, updates the count, and then passes that state back down to both <code>Button</code> components.</p>
<h3 id="heading-tiny-crash-course-in-typescript">Tiny Crash Course in TypeScript</h3>
<p>If you check <code>components/button.tsx</code> you will see the following errors for both the <code>count</code> and <code>onClick</code> props you are reading into <code>Button</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screenshot-2024-06-14-at-2.49.55-PM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Binding element 'count' implicitly has an 'any' type.</em></p>
<p>(You can get these "pretty" TypeScript syntax-highlighted errors with the Visual Studio Code extension <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=yoavbls.pretty-ts-errors">here</a>).</p>
<p>What do these errors mean, and what is TypeScript? TypeScript is a superset of JavaScript that adds <em>types</em> to JavaScript. These can help ensure that our program works as we intend. Examples of types are <code>number</code>, <code>boolean</code>, and <code>string</code>. This error is telling us that we haven't defined a type for the props <code>count</code> or <code>onClick</code>. </p>
<p>So what will the type of <code>count</code> be? If we consider the result of count, the answers could be <code>1</code>, <code>2</code>, <code>3</code>, and so on. These are all numbers, so we will assign the type <code>number</code> to <code>count</code>.</p>
<p>The <code>onClick</code> prop is a function that doesn't take any arguments or return any value – we use it for its side effect of updating <code>setCount</code>. So we assign it the type <code>() =&gt; void</code>. </p>
<p>We create an <em><a target="_blank" href="https://www.typescriptlang.org/docs/handbook/interfaces.html">interface</a></em> where we define the types for our <code>ButtonProps</code>, and then read this interface into our component:</p>
<pre><code class="lang-js">interface ButtonProps {
    <span class="hljs-attr">count</span>: number;
    onClick: <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">Button</span>(<span class="hljs-params">{ count, onClick }: ButtonProps</span>) </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">onClick</span>=<span class="hljs-string">{onClick}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 rounded text-white font-bold px-4 py-2"</span>
        &gt;</span>
            I have been clicked {count} times
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
}
</code></pre>
<p>The errors are gone and there you have it: a tiny intro to TypeScript!</p>
<p>Here let's make another commit with a message such as <code>buttons with shared state</code>.</p>
<h2 id="heading-chapter-4-how-to-add-both-pairs-of-buttons-to-our-site">Chapter 4: How to Add Both Pairs of Buttons to Our Site</h2>
<p>Let's showcase both our buttons with shared and independent state, and deploy the application.</p>
<p>Let's rename our <code>button.tsx</code> to <code>button-shared-state.tsx</code>. Let's also rename the function, the interface, the import within <code>app/page.tsx</code>, as well as the component in <code>app/page.tsx</code>. And let's switch these to <em>named</em> exports using a function expression using <code>const</code> instead of a function declaration:</p>
<pre><code class="lang-js">interface ButtonSharedStateProps {
    <span class="hljs-attr">count</span>: number;
    onClick: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">void</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ButtonSharedState = <span class="hljs-function">(<span class="hljs-params">{
    count,
    onClick,
}: ButtonSharedStateProps</span>) =&gt;</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">onClick</span>=<span class="hljs-string">{onClick}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 rounded text-white font-bold px-4 py-2"</span>
        &gt;</span>
            I have been clicked {count} times
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
};
</code></pre>
<pre><code class="lang-js"><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> { ButtonSharedState } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/button-shared-state"</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">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params"></span>) </span>{
        setCount(count + <span class="hljs-number">1</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">"flex min-h-screen flex-col items-center p-24 gap-4"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>React Counter Button<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ButtonSharedState</span> <span class="hljs-attr">count</span>=<span class="hljs-string">{count}</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ButtonSharedState</span> <span class="hljs-attr">count</span>=<span class="hljs-string">{count}</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
    );
}
</code></pre>
<p>Now let's create a file <code>components/button-independent-state.tsx</code>:</p>
<pre><code class="lang-js"><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">export</span> <span class="hljs-keyword">const</span> ButtonIndependentState = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params"></span>) </span>{
        setCount(count + <span class="hljs-number">1</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">className</span>=<span class="hljs-string">"bg-blue-500 hover:bg-blue-700 rounded text-white font-bold py-2 px-4"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span>
        &gt;</span>
            I have been clicked {count} times
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
    );
};
</code></pre>
<p>What we've done here is similar to our logic in the beginning of this guide: we've located the state within the button component itself, so that each implementation of the button component creates and tracks its own independent state.</p>
<p>Let's import <code>ButtonIndependentState</code> into <code>app/page.tsx</code>:</p>
<pre><code class="lang-js"><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> { ButtonSharedState } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/button-shared-state"</span>;
<span class="hljs-keyword">import</span> { ButtonIndependentState } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/button-independent-state"</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">const</span> [count, setCount] = useState(<span class="hljs-number">0</span>);

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handleClick</span>(<span class="hljs-params"></span>) </span>{
        setCount(count + <span class="hljs-number">1</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">"flex min-h-screen flex-col items-center p-24 gap-4"</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"</span>&gt;</span>React Counter Buttons<span class="hljs-tag">&lt;/<span class="hljs-name">h1</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"</span>&gt;</span>Buttons with shared state<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ButtonSharedState</span> <span class="hljs-attr">count</span>=<span class="hljs-string">{count}</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ButtonSharedState</span> <span class="hljs-attr">count</span>=<span class="hljs-string">{count}</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClick}</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"</span>&gt;</span>Buttons with independent state<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ButtonIndependentState</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ButtonIndependentState</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>
    );
}
</code></pre>
<p>We have now showcased a set of buttons that have independent state, as well as buttons that have shared state. We added a tiny bit of CSS to make things look nicer as well.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Screen-Recording-2024-06-21-at-12.25.22-PM.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Our finished project</em></p>
<p>Here let's add another commit with a message such as <code>buttons with both shared and independent state</code>.</p>
<h2 id="heading-chapter-5-how-to-deploy-the-site-to-netlify">Chapter 5: How to Deploy the Site to Netlify</h2>
<h3 id="heading-publish-to-github">Publish to GitHub</h3>
<p>Let's deploy our application to the world to show it off. We are going to push our code to GitHub, and then deploy it to Netlify.</p>
<p>The first step is push our code to GitHub. If you don't have a GitHub account, create one first. In Visual Studio Code, you can push to GitHub from the command palette: open up the command palette by pressing <code>⇧⌘P</code> , then type in <code>publish to GitHub</code>, and select <code>publish to public GitHub repository</code>. </p>
<p>Open your GitHub account and verify that the project has successfully been uploaded.</p>
<h3 id="heading-deploy-to-netlify">Deploy to Netlify</h3>
<p>Once you've uploaded your project to GitHub, you can now deploy it to Netlify. Open up the <a target="_blank" href="https://www.netlify.com/">Netlify website</a>, and log in (or create an account if you don't have one).</p>
<p>Click <code>add new site</code>, and then <code>import an existing project</code>. When asked <code>Let’s deploy your project with…</code>, select <code>GitHub</code>. </p>
<p>Select the name of your repository from the list, then give the site a name under <code>site name</code>. You can leave the rest of the settings at their defaults and then click <code>deploy [your site name]</code>.</p>
<p>If the project builds successfully, you will have a live link of your work!</p>
<h2 id="heading-concluding-thoughts-and-next-steps">Concluding Thoughts and Next Steps</h2>
<p>In this project, you have learned fundamental concepts in React such as creating a functional component, importing and exporting modules, interpolating JavaScript within JSX using curly braces, working with state, and using React hooks. </p>
<p>You've also seen an introduction to using utility-based CSS techniques with Tailwind CSS, and you've gotten a tiny introduction into adding types to your JavaScript with TypeScript. Finally, you learned how to deploy your project to Netlify via GitHub.</p>
<p>Where can you go from here? One idea for expanding the project could be to create a "ticker": a counter that could be incremented and decremented (you would have one button that increases the number of the counter, and one that decreases it). </p>
<p>In the name of learning, one effective method for solidifying the concepts you've learned here would be to start a project completely fresh, and see if you can build everything in this tutorial without checking the tutorial. As you need to check in, you will identify which concepts benefit from further study and practice.</p>
<p>If you'd like to stay in touch, you can:</p>
<ul>
<li>Follow me on <a target="_blank" href="https://twitter.com/DevinCLane">Twitter</a> </li>
<li>Follow me on <a target="_blank" href="https://www.linkedin.com/in/devinlane/">LinkedIn</a></li>
</ul>
<p>Please post about what you've made along with any questions or feedback you might have.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Data Flow in Redux Explained – A State Management Handbook ]]>
                </title>
                <description>
                    <![CDATA[ In complex React applications, managing application state effectively can become a challenge. This is where Redux, a predictable state management library, steps in. By introducing a unidirectional data flow, Redux brings order and clarity to how data... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-data-flows-in-redux/</link>
                <guid isPermaLink="false">66c4c3d48e05d0e4345147c6</guid>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Redux ]]>
                    </category>
                
                    <category>
                        <![CDATA[ State Management  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joan Ayebola ]]>
                </dc:creator>
                <pubDate>Wed, 03 Jul 2024 13:45:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/Data-Flow-in-Redux-Explained-Cover-No-Photo.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In complex React applications, managing application state effectively can become a challenge. This is where Redux, a predictable state management library, steps in.</p>
<p>By introducing a unidirectional data flow, Redux brings order and clarity to how data updates and interacts within your React components.</p>
<p>This article discusses the inner workings of Redux, specifically focusing on how data flows throughout your application. We'll explore core concepts like the Redux store, actions, reducers, and selectors, along with practical examples of how they work together to seamlessly manage your application state.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-redux">What is Redux?</a></li>
<li><a class="post-section-overview" href="#heading-why-use-redux-for-data-management">Why Use Redux for Data Management?</a></li>
<li><a class="post-section-overview" href="#heading-core-concepts-of-redux-data-flow">Core Concepts of Redux Data Flow</a>  </li>
<li><a class="post-section-overview" href="#heading-unidirectional-data-flow">Unidirectional Data Flow</a>  </li>
<li><a class="post-section-overview" href="#heading-benefits-of-unidirectional-data-flow">Benefits of Unidirectional Data Flow</a></li>
<li><a class="post-section-overview" href="#heading-state-management-with-redux-store">State Management with Redux Store</a>  </li>
<li><a class="post-section-overview" href="#heading-what-is-the-redux-store">What is the Redux Store?</a>  </li>
<li><a class="post-section-overview" href="#heading-store-structure-state-reducers-actions">Store Structure (State, Reducers, Actions)</a></li>
<li><a class="post-section-overview" href="#heading-actions-initiating-state-changes">Actions: Initiating State Changes</a>  </li>
<li><a class="post-section-overview" href="#heading-action-creators-functions-to-create-actions">Action Creators (Functions to Create Actions)</a>  </li>
<li><a class="post-section-overview" href="#heading-action-types-identifying-different-actions">Action Types (Identifying Different Actions)</a></li>
<li><a class="post-section-overview" href="#heading-how-to-process-state-changes">How to Process State Changes</a>  </li>
<li><a class="post-section-overview" href="#heading-pure-functions-reducers-at-the-core">Pure Functions: Reducers at the Core</a>  </li>
<li><a class="post-section-overview" href="#heading-characteristics-of-pure-functions">Characteristics of Pure Functions</a> </li>
<li><a class="post-section-overview" href="#heading-anatomy-of-a-reducer-function">Anatomy of a Reducer Function</a>  </li>
<li><a class="post-section-overview" href="#heading-parameters-previous-state-and-action-object">Parameters: Previous State and Action Object</a>  </li>
<li><a class="post-section-overview" href="#heading-return-value-updated-state">Return Value: Updated State</a></li>
<li><a class="post-section-overview" href="#heading-how-to-handle-different-actions-in-reducers">How to Handle Different Actions in Reducers</a>  </li>
<li><a class="post-section-overview" href="#heading-using-switch-statements">Using Switch Statements or Conditional Logic</a></li>
<li><a class="post-section-overview" href="#heading-dispatching-actions-how-to-update-the-redux-store">Dispatching Actions: How to Update the Redux Store</a>  </li>
<li><a class="post-section-overview" href="#heading-the-dispatch-function">The <code>dispatch</code> Function</a>  </li>
<li><a class="post-section-overview" href="#heading-dispatching-actions-from-components-or-events">Dispatching Actions from Components or Events</a></li>
<li><a class="post-section-overview" href="#heading-how-to-access-specific-data-from-the-store">How to Access Specific Data from the Store</a>  </li>
<li><a class="post-section-overview" href="#heading-creating-selector-functions">Creating Selector Functions</a>  </li>
<li><a class="post-section-overview" href="#heading-memoization-for-efficient-selector-usage">Memoization for Efficient Selector Usage</a></li>
<li><a class="post-section-overview" href="#heading-how-to-connect-react-components-to-redux">How to Connect React Components to Redux</a>  </li>
<li><a class="post-section-overview" href="#heading-the-connect-function-from-react-redux-library">The <code>connect</code> Function from <code>react-redux</code> Library</a>  </li>
<li><a class="post-section-overview" href="#heading-mapping-state-and-dispatch-to-props">Mapping State and Dispatch to Props</a>  </li>
<li><a class="post-section-overview" href="#heading-using-connected-components-in-your-application">Using Connected Components in Your Application</a></li>
<li><a class="post-section-overview" href="#heading-advanced-redux-data-flow-techniques">Advanced Redux Data Flow Techniques</a>  </li>
<li><a class="post-section-overview" href="#heading-asynchronous-actions-redux-thunk-redux-saga">Asynchronous Actions (Redux Thunk, Redux Saga)</a>  </li>
<li><a class="post-section-overview" href="#heading-middleware-for-extending-redux-functionality">Middleware for Extending Redux Functionality</a></li>
<li><a class="post-section-overview" href="#heading-best-practices-for-managing-data-flow-in-redux">Best Practices for Managing Data Flow in Redux</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-what-is-redux">What is Redux?</h2>
<p>Redux is a predictable state container for JavaScript applications, primarily used with libraries like React. It helps manage the application state in a centralized store, making it easier to manage and update state across your entire application.</p>
<p>In simple terms, Redux provides a way to store and manage the data that your application needs to work. It follows a strict pattern to ensure that state changes are predictable and manageable.</p>
<h2 id="heading-why-use-redux-for-data-management">Why Use Redux for Data Management?</h2>
<p>Using Redux for data management in your application offers several advantages:</p>
<p><strong>Centralized State Management</strong>: Redux stores the application's state in a single store, making it easier to manage and debug compared to having scattered state across multiple components.</p>
<p><strong>Predictable State Changes</strong>: State mutations are done through reducers, which are pure functions. This ensures that state changes are predictable and traceable, making it easier to understand how data flows through your application.</p>
<p><strong>Easier Debugging</strong>: With a single source of truth, debugging becomes simpler. You can log state changes, track actions, and even implement time-travel debugging (via Redux DevTools) to replay actions and inspect state at any point in time.</p>
<p><strong>Facilitates Testing</strong>: Since reducers are pure functions that depend only on their input and produce predictable output, testing becomes straightforward. You can easily test how reducers update the state in response to different actions.</p>
<p><strong>Enforces Unidirectional Data Flow</strong>: Redux follows a strict unidirectional data flow pattern. Data flows in one direction: actions are dispatched, reducers update the state immutably, and components subscribe to the changes they're interested in. This pattern simplifies data management and reduces bugs related to inconsistent state.</p>
<p><strong>Eases State Persistence</strong>: Redux makes it easier to persist your application state across sessions or store it locally, enhancing the user experience by preserving data between visits.</p>
<p><strong>Scalability</strong>: Redux scales well with large applications because of its centralized state management. As your application grows, managing state becomes more manageable and less error-prone compared to using local component state or prop drilling.</p>
<h2 id="heading-core-concepts-of-redux-data-flow">Core Concepts of Redux Data Flow</h2>
<p>Understanding the core concepts of Redux data flow is essential for mastering state management in modern JavaScript applications.</p>
<h3 id="heading-unidirectional-data-flow">Unidirectional Data Flow</h3>
<p>Redux follows a strict unidirectional data flow pattern, which means that data in your application moves in a single direction through a series of steps:</p>
<ol>
<li><strong>Actions</strong>: Actions are plain JavaScript objects that represent an intention to change the state. They are the only source of information for the store.</li>
<li><strong>Reducers</strong>: Reducers are pure functions responsible for handling state transitions based on actions. They specify how the application's state changes in response to actions sent to the store.</li>
<li><strong>Store</strong>: The store holds the application state. It allows access to the state via <code>getState()</code>, updates the state via <code>dispatch(action)</code>, and registers listeners via <code>subscribe(listener)</code>.</li>
<li><strong>View</strong>: React components (or any other UI layer) subscribe to the store to receive updates when the state changes. They then re-render based on the updated state.</li>
</ol>
<p>Here’s a simplified overview of how the unidirectional data flow works in Redux:</p>
<ol>
<li><strong>Action Dispatch</strong>: Components dispatch actions to the Redux store using <code>store.dispatch(action)</code>. Actions are plain JavaScript objects with a <code>type</code> field that describes the type of action being performed.</li>
<li><strong>Action Handling</strong>: The store passes the dispatched action to the root reducer. The reducer is a pure function that takes the current state and the action, computes the new state based on the action, and returns the updated state.</li>
<li><strong>State Update</strong>: The Redux store updates its state based on the return value of the root reducer. It notifies all subscribed components of the state change.</li>
<li><strong>Component Re-render</strong>: Components that are subscribed to the store receive the updated state as props. They re-render with the new data.</li>
</ol>
<h3 id="heading-benefits-of-unidirectional-data-flow">Benefits of Unidirectional Data Flow</h3>
<p><strong>Predictability</strong>: By enforcing a single direction for data flow, Redux makes state changes more predictable and easier to understand. Actions are explicit about what changes are happening, and reducers clearly define how the state transitions occur.</p>
<p><strong>Debugging</strong>: Unidirectional data flow simplifies debugging because you can trace how state changes propagate through your application. Redux DevTools enhance this further by allowing you to track actions, inspect state changes over time, and even replay actions to reproduce bugs.</p>
<p><strong>Maintainability</strong>: With a clear separation between data (state) and logic (reducers), Redux promotes cleaner, more maintainable code. It reduces the likelihood of bugs caused by inconsistent state mutations or side effects.</p>
<p><strong>Scalability</strong>: As your application grows in size and complexity, unidirectional data flow helps manage state updates more effectively. It avoids the pitfalls of two-way data binding and ensures that changes to the state are controlled and manageable.</p>
<p><strong>Testing</strong>: Since reducers are pure functions that take inputs and produce outputs without side effects, unit testing becomes straightforward. You can test reducers with different actions and state scenarios to ensure they behave as expected.</p>
<h2 id="heading-state-management-with-redux-store">State Management with Redux Store</h2>
<p>State management plays a pivotal role in modern web development, ensuring applications maintain consistent and predictable states across various components.</p>
<h3 id="heading-what-is-the-redux-store">What is the Redux Store?</h3>
<p>The Redux Store is the heart of Redux state management. It holds the entire state tree of your application. The store allows you to:</p>
<ul>
<li>Access the current state of your application via <code>store.getState()</code>.</li>
<li>Dispatch actions to change the state using <code>store.dispatch(action)</code>.</li>
<li>Subscribe to changes in the state so your components can update accordingly using <code>store.subscribe(listener)</code>.</li>
</ul>
<p>In essence, the Redux Store acts as a centralized repository for the state of your application, facilitating predictable data flow and making state management more manageable.</p>
<h3 id="heading-store-structure-state-reducers-actions">Store Structure (State, Reducers, Actions)</h3>
<p>The <strong>state</strong> in Redux represents the entire state of your application. It is typically structured as a plain JavaScript object. The shape of the state is defined by the reducers. For example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> initialState = {
  <span class="hljs-attr">todos</span>: [],
  <span class="hljs-attr">visibilityFilter</span>: <span class="hljs-string">'SHOW_ALL'</span>,
};
</code></pre>
<p>In this example, <code>todos</code> and <code>visibilityFilter</code> are pieces of state managed by Redux.</p>
<p><strong>Reducers</strong> are functions that specify how the application's state changes in response to actions dispatched to the store. They take the current state and an action as arguments, and return the new state based on the action type. </p>
<p>Reducers must be pure functions, meaning they produce the same output for the same input and do not modify the state directly.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> todosReducer = <span class="hljs-function">(<span class="hljs-params">state = [], action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_TODO'</span>:
      <span class="hljs-keyword">return</span> [
        ...state,
        {
          <span class="hljs-attr">id</span>: action.id,
          <span class="hljs-attr">text</span>: action.text,
          <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>
        }
      ];
    <span class="hljs-keyword">case</span> <span class="hljs-string">'TOGGLE_TODO'</span>:
      <span class="hljs-keyword">return</span> state.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span>
        (todo.id === action.id)
          ? { ...todo, <span class="hljs-attr">completed</span>: !todo.completed }
          : todo
      );
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state;
  }
};
</code></pre>
<p>In this example, <code>todosReducer</code> manages the <code>todos</code> piece of state, handling actions like <code>'ADD_TODO'</code> and <code>'TOGGLE_TODO'</code> to add new todos or toggle their completion status.</p>
<p><strong>Actions</strong> are plain JavaScript objects that describe what happened in your application. They are the only source of information for the store. Actions typically have a <code>type</code> field that indicates the type of action being performed, and they may also carry additional data necessary for the action.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> addTodo = <span class="hljs-function">(<span class="hljs-params">text</span>) =&gt;</span> ({
  <span class="hljs-attr">type</span>: <span class="hljs-string">'ADD_TODO'</span>,
  <span class="hljs-attr">id</span>: nextTodoId++,
  text
});

<span class="hljs-keyword">const</span> toggleTodo = <span class="hljs-function">(<span class="hljs-params">id</span>) =&gt;</span> ({
  <span class="hljs-attr">type</span>: <span class="hljs-string">'TOGGLE_TODO'</span>,
  id
});
</code></pre>
<p>In this example, <code>addTodo</code> and <code>toggleTodo</code> are action creator functions that return actions to add a new todo and toggle the completion status of a todo, respectively.</p>
<p>The relationship between these elements in Redux is crucial for managing application state effectively:</p>
<ul>
<li><strong>Actions</strong> describe events that occur in your application.</li>
<li><strong>Reducers</strong> specify how the application's state changes in response to actions.</li>
<li><strong>Store</strong> holds the application state and allows you to dispatch actions to update the state.</li>
</ul>
<p>Together, these components form the core structure of Redux state management, providing a clear and predictable way to manage and update application state across your entire application.</p>
<h2 id="heading-actions-initiating-state-changes">Actions: Initiating State Changes</h2>
<p>Managing state effectively lies at the core of creating dynamic and responsive applications. Actions, within the Redux architecture and similar state management libraries, serve as important elements for initiating state changes.</p>
<h3 id="heading-action-creators-functions-to-create-actions">Action Creators (Functions to Create Actions)</h3>
<p>Action creators in Redux are functions that create and return action objects. These action objects describe what happened in your application and are dispatched to the Redux store to initiate state changes. </p>
<p>Action creators encapsulate the logic of creating actions, making your code more modular and easier to test.</p>
<p>Here's an example of an action creator:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Action creator function</span>
<span class="hljs-keyword">const</span> addTodo = <span class="hljs-function">(<span class="hljs-params">text</span>) =&gt;</span> ({
  <span class="hljs-attr">type</span>: <span class="hljs-string">'ADD_TODO'</span>,
  <span class="hljs-attr">id</span>: nextTodoId++,
  text
});

<span class="hljs-comment">// Usage of the action creator</span>
<span class="hljs-keyword">const</span> newTodoAction = addTodo(<span class="hljs-string">'Buy groceries'</span>);
</code></pre>
<p>In this example:</p>
<ul>
<li><code>addTodo</code> is an action creator function that takes <code>text</code> as a parameter and returns an action object.</li>
<li>The action object has a <code>type</code> field (<code>'ADD_TODO'</code>) that identifies the type of action and additional fields (<code>id</code> and <code>text</code>) that provide necessary data for the action.</li>
</ul>
<p>Action creators simplify the process of creating actions, especially when actions require complex data or calculations before dispatching.</p>
<h3 id="heading-action-types-identifying-different-actions">Action Types (Identifying Different Actions)</h3>
<p>Action types in Redux are string constants that define the type of action being performed. They are used to identify and differentiate different actions that can be dispatched to the Redux store. By using string constants for action types, Redux ensures that action types are unique and easy to reference throughout your application.</p>
<p>Here's how action types are typically defined:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Action types as constants</span>
<span class="hljs-keyword">const</span> ADD_TODO = <span class="hljs-string">'ADD_TODO'</span>;
<span class="hljs-keyword">const</span> TOGGLE_TODO = <span class="hljs-string">'TOGGLE_TODO'</span>;
<span class="hljs-keyword">const</span> SET_VISIBILITY_FILTER = <span class="hljs-string">'SET_VISIBILITY_FILTER'</span>;
</code></pre>
<p>These constants (<code>ADD_TODO</code>, <code>TOGGLE_TODO</code>, <code>SET_VISIBILITY_FILTER</code>) represent different actions that can occur in your application, such as adding a todo, toggling the completion status of a todo, or setting a visibility filter for todos.</p>
<p>Action types are typically used in action objects created by action creators and are matched in reducers to determine how the state should change in response to each action.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Example of using action types in a reducer</span>
<span class="hljs-keyword">const</span> todosReducer = <span class="hljs-function">(<span class="hljs-params">state = [], action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> ADD_TODO:
      <span class="hljs-keyword">return</span> [
        ...state,
        {
          <span class="hljs-attr">id</span>: action.id,
          <span class="hljs-attr">text</span>: action.text,
          <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>
        }
      ];
    <span class="hljs-keyword">case</span> TOGGLE_TODO:
      <span class="hljs-keyword">return</span> state.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span>
        (todo.id === action.id)
          ? { ...todo, <span class="hljs-attr">completed</span>: !todo.completed }
          : todo
      );
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state;
  }
};
</code></pre>
<p>In this example:</p>
<ul>
<li><code>ADD_TODO</code> and <code>TOGGLE_TODO</code> are action types used in the <code>todosReducer</code> to handle different types of actions (<code>'ADD_TODO'</code> and <code>'TOGGLE_TODO'</code>).</li>
<li>The <code>action.type</code> field in the switch statement ensures that the reducer responds appropriately to each dispatched action based on its type.</li>
</ul>
<h2 id="heading-how-to-process-state-changes">How to Process State Changes</h2>
<p>At the heart of state management are reducers, pure functions designed to handle state transitions in a controlled and immutable manner.</p>
<h3 id="heading-pure-functions-reducers-at-the-core">Pure Functions: Reducers at the Core</h3>
<p>Reducers in Redux are pure functions responsible for specifying how the application's state changes in response to actions dispatched to the store. They take the current state and an action as arguments, and return the new state based on the action type.</p>
<p>Here’s a breakdown of how reducers work and their role in managing state changes:</p>
<p><strong>Pure Functions</strong>: Reducers are pure functions, which means they:</p>
<ul>
<li>Produce the same output for the same input every time they are called.</li>
<li>Do not cause any side effects (such as modifying arguments or global variables).</li>
<li>Do not mutate the state directly, but instead return a new state object.</li>
</ul>
<p><strong>Handling State Transitions</strong>: Reducers specify how the application's state changes in response to different types of actions. They use the current state and the action dispatched to compute and return the new state.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Example of a todos reducer</span>
<span class="hljs-keyword">const</span> todosReducer = <span class="hljs-function">(<span class="hljs-params">state = [], action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_TODO'</span>:
      <span class="hljs-keyword">return</span> [
        ...state,
        {
          <span class="hljs-attr">id</span>: action.id,
          <span class="hljs-attr">text</span>: action.text,
          <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>
        }
      ];
    <span class="hljs-keyword">case</span> <span class="hljs-string">'TOGGLE_TODO'</span>:
      <span class="hljs-keyword">return</span> state.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span>
        (todo.id === action.id)
          ? { ...todo, <span class="hljs-attr">completed</span>: !todo.completed }
          : todo
      );
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state;
  }
};
</code></pre>
<p>In this example:</p>
<ul>
<li><code>todosReducer</code> is a pure function that takes <code>state</code> (current todos array) and <code>action</code> as arguments.</li>
<li>Depending on the <code>action.type</code>, it computes and returns a new state (updated todos array).</li>
</ul>
<p><strong>Immutable State Updates</strong>: Reducers should never mutate the state directly. Instead, they create copies of the state and modify the copies to produce a new state object. This ensures that Redux can detect state changes and update components efficiently.</p>
<p><strong>Single Responsibility Principle</strong>: Each reducer typically handles updates to a specific slice of the application state. This helps maintain a clear separation of concerns and makes reducers easier to understand, test, and maintain.</p>
<h3 id="heading-characteristics-of-pure-functions">Characteristics of Pure Functions</h3>
<p>Pure functions, including Redux reducers, have specific characteristics that make them well-suited for managing state changes:</p>
<p><strong>Deterministic</strong>: A pure function always produces the same output for the same input. This predictability ensures that reducers behave consistently and are easier to reason about.</p>
<p><strong>No Side Effects</strong>: Pure functions do not modify the input arguments or any external state. They only depend on their input parameters and produce an output without causing observable side effects.</p>
<p><strong>Immutable Data</strong>: Pure functions do not mutate data. Instead, they create and return new data structures. In Redux, reducers produce a new state object without modifying the existing state, enabling efficient change detection and state management.</p>
<p><strong>Referential Transparency</strong>: Pure functions can be replaced with their return values without affecting the correctness of the program. This property supports composability and makes it easier to test and reason about code.</p>
<h2 id="heading-anatomy-of-a-reducer-function">Anatomy of a Reducer Function</h2>
<p>A reducer function, at its core, defines how application state changes in response to dispatched actions. This function takes two parameters: the current state and an action object, determining the new state based on the type of action received.</p>
<h3 id="heading-parameters-previous-state-and-action-object">Parameters: Previous State and Action Object</h3>
<p>A reducer function in Redux is a pure function that takes two parameters: the previous state (state before the action is applied) and an action object. These parameters define how the reducer computes the next state of the application.</p>
<p><strong>Previous State</strong>: This parameter represents the current state of the application before the action is dispatched. It is immutable and should not be modified directly within the reducer.</p>
<p><strong>Action Object</strong>: An action object is a plain JavaScript object that describes what happened in your application. It typically has a <code>type</code> field that indicates the type of action being performed. Other fields in the action object may provide additional data necessary to update the state.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> action = {
  <span class="hljs-attr">type</span>: <span class="hljs-string">'ADD_TODO'</span>,
  <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">text</span>: <span class="hljs-string">'Buy groceries'</span>
};
</code></pre>
<p>In this example, <code>action.type</code> is <code>'ADD_TODO'</code>, indicating that we want to add a new todo item to the state.</p>
<h3 id="heading-return-value-updated-state">Return Value: Updated State</h3>
<p>The reducer function must return the updated state based on the previous state and the action object passed to it. The updated state is typically a new object that represents the application's state after applying the action.</p>
<p>Here’s the basic structure of a reducer function:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> initialState = {
  <span class="hljs-attr">todos</span>: [],
  <span class="hljs-attr">visibilityFilter</span>: <span class="hljs-string">'SHOW_ALL'</span>
};

<span class="hljs-keyword">const</span> todoAppReducer = <span class="hljs-function">(<span class="hljs-params">state = initialState, action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_TODO'</span>:
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">todos</span>: [
          ...state.todos,
          {
            <span class="hljs-attr">id</span>: action.id,
            <span class="hljs-attr">text</span>: action.text,
            <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>
          }
        ]
      };
    <span class="hljs-keyword">case</span> <span class="hljs-string">'TOGGLE_TODO'</span>:
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">todos</span>: state.todos.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span>
          (todo.id === action.id)
            ? { ...todo, <span class="hljs-attr">completed</span>: !todo.completed }
            : todo
        )
      };
    <span class="hljs-keyword">case</span> <span class="hljs-string">'SET_VISIBILITY_FILTER'</span>:
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">visibilityFilter</span>: action.filter
      };
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state;
  }
};
</code></pre>
<p>In this example:</p>
<ul>
<li><code>todoAppReducer</code> is a reducer function that manages the state of todos and visibility filters.</li>
<li>It takes <code>state</code> (previous state) and <code>action</code> as parameters.</li>
<li>Depending on the <code>action.type</code>, it computes and returns a new state object that reflects the changes caused by the action.</li>
</ul>
<h3 id="heading-key-points">Key Points:</h3>
<p><strong>Immutable Update</strong>: Reducers should never modify the previous state directly. Instead, they create a new state object by copying the previous state (<code>...state</code>) and applying changes to it.</p>
<p><strong>Default Case</strong>: The <code>default</code> case in the <code>switch</code> statement returns the current state unchanged if the reducer doesn’t recognize the action type. This ensures that the reducer always returns a valid state object, even if no changes are made.</p>
<p><strong>Single Responsibility</strong>: Each case in the <code>switch</code> statement corresponds to a specific action type and is responsible for updating a specific slice of the application state. This promotes a clear separation of concerns and makes reducers easier to understand and maintain.</p>
<h2 id="heading-how-to-handle-different-actions-in-reducers">How to Handle Different Actions in Reducers</h2>
<p>In Redux, you can handle different actions in reducers using either switch statements or conditional logic. Both approaches aim to determine how the application state should change based on the type of action dispatched.</p>
<h3 id="heading-using-switch-statements">Using Switch Statements</h3>
<p>Switch statements are commonly used in Redux reducers to handle different action types. Each <code>case</code> in the switch statement corresponds to a specific action type, and the reducer executes the corresponding logic based on the action type.</p>
<p>Here's an example of using switch statements in a reducer:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> initialState = {
  <span class="hljs-attr">todos</span>: [],
  <span class="hljs-attr">visibilityFilter</span>: <span class="hljs-string">'SHOW_ALL'</span>
};

<span class="hljs-keyword">const</span> todoAppReducer = <span class="hljs-function">(<span class="hljs-params">state = initialState, action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'ADD_TODO'</span>:
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">todos</span>: [
          ...state.todos,
          {
            <span class="hljs-attr">id</span>: action.id,
            <span class="hljs-attr">text</span>: action.text,
            <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>
          }
        ]
      };
    <span class="hljs-keyword">case</span> <span class="hljs-string">'TOGGLE_TODO'</span>:
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">todos</span>: state.todos.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span>
          (todo.id === action.id)
            ? { ...todo, <span class="hljs-attr">completed</span>: !todo.completed }
            : todo
        )
      };
    <span class="hljs-keyword">case</span> <span class="hljs-string">'SET_VISIBILITY_FILTER'</span>:
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">visibilityFilter</span>: action.filter
      };
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state;
  }
};
</code></pre>
<p>In this example:</p>
<ul>
<li>The <code>todoAppReducer</code> function uses a switch statement to handle different action types (<code>'ADD_TODO'</code>, <code>'TOGGLE_TODO'</code>, <code>'SET_VISIBILITY_FILTER'</code>).</li>
<li>Each <code>case</code> block specifies how the state should be updated in response to the corresponding action type.</li>
<li>The <code>default</code> case returns the current state unchanged if the reducer doesn’t recognize the action type, ensuring that the reducer always returns a valid state object.</li>
</ul>
<h3 id="heading-using-conditional-logic">Using Conditional Logic</h3>
<p>Alternatively, reducers can also use conditional logic (if-else statements) to determine how to update the state based on the action type. While less common than switch statements in Redux, conditional logic can be used similarly to handle actions.</p>
<p>Here's an example of using conditional logic in a reducer:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> todoAppReducer = <span class="hljs-function">(<span class="hljs-params">state = initialState, action</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (action.type === <span class="hljs-string">'ADD_TODO'</span>) {
    <span class="hljs-keyword">return</span> {
      ...state,
      <span class="hljs-attr">todos</span>: [
        ...state.todos,
        {
          <span class="hljs-attr">id</span>: action.id,
          <span class="hljs-attr">text</span>: action.text,
          <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>
        }
      ]
    };
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (action.type === <span class="hljs-string">'TOGGLE_TODO'</span>) {
    <span class="hljs-keyword">return</span> {
      ...state,
      <span class="hljs-attr">todos</span>: state.todos.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span>
        (todo.id === action.id)
          ? { ...todo, <span class="hljs-attr">completed</span>: !todo.completed }
          : todo
      )
    };
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (action.type === <span class="hljs-string">'SET_VISIBILITY_FILTER'</span>) {
    <span class="hljs-keyword">return</span> {
      ...state,
      <span class="hljs-attr">visibilityFilter</span>: action.filter
    };
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> state;
  }
};
</code></pre>
<p>In this example:</p>
<ul>
<li>The <code>todoAppReducer</code> function uses if-else statements to check the action type (<code>action.type</code>) and execute different logic based on the type of action.</li>
<li>Each condition specifies how the state should be updated for the corresponding action type.</li>
<li>The final <code>else</code> block returns the current state unchanged if the action type is not recognized.</li>
</ul>
<h3 id="heading-choosing-between-switch-statements-and-conditional-logic">Choosing Between Switch Statements and Conditional Logic</h3>
<h4 id="heading-1-switch-statements">1. Switch Statements:</h4>
<ul>
<li>Advantages: Switch statements are typically more readable and maintainable when handling multiple action types in Redux reducers. They clearly separate different cases based on action types.</li>
<li>Considerations: Ensure each action type has a corresponding <code>case</code> in the switch statement to handle updates correctly.</li>
</ul>
<h4 id="heading-2-conditional-logic">2. Conditional Logic:</h4>
<ul>
<li>Advantages: Conditional logic (if-else statements) provides flexibility and can be easier to understand in certain scenarios where there are fewer action types.</li>
<li>Considerations: Maintain consistency in handling action types and ensure each condition handles state updates correctly.</li>
</ul>
<p>In practice, switch statements are the recommended approach in Redux reducers due to their clarity and convention within the Redux community. They help maintain a structured approach to managing state changes based on different action types, promoting consistency and predictability in Redux applications.</p>
<h2 id="heading-dispatching-actions-how-to-update-the-redux-store">Dispatching Actions: How to Update the Redux Store</h2>
<p>Dispatching actions in Redux is fundamental to managing state updates within your application. Redux, a predictable state container for JavaScript applications, relies on actions as payloads of information that send data from your application to the Redux store.</p>
<h3 id="heading-the-dispatch-function">The <code>dispatch</code> function</h3>
<p>In Redux, the <code>dispatch</code> function is a method provided by the Redux store. It is used to dispatch actions to trigger state changes in the application. When an action is dispatched, the Redux store calls the reducer function associated with it, computes the new state, and notifies all subscribers that the state has been updated.</p>
<p>Here's how you use the <code>dispatch</code> function:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createStore } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>;

<span class="hljs-comment">// Reducer function</span>
<span class="hljs-keyword">const</span> counterReducer = <span class="hljs-function">(<span class="hljs-params">state = { count: <span class="hljs-number">0</span> }, action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'INCREMENT'</span>:
      <span class="hljs-keyword">return</span> { ...state, <span class="hljs-attr">count</span>: state.count + <span class="hljs-number">1</span> };
    <span class="hljs-keyword">case</span> <span class="hljs-string">'DECREMENT'</span>:
      <span class="hljs-keyword">return</span> { ...state, <span class="hljs-attr">count</span>: state.count - <span class="hljs-number">1</span> };
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state;
  }
};

<span class="hljs-comment">// Create Redux store</span>
<span class="hljs-keyword">const</span> store = createStore(counterReducer);

<span class="hljs-comment">// Dispatch actions to update state</span>
store.dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">'INCREMENT'</span> });
store.dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">'DECREMENT'</span> });
</code></pre>
<p>In this example:</p>
<ul>
<li>We create a Redux store using <code>createStore</code> and pass in the <code>counterReducer</code> function.</li>
<li>The <code>store.dispatch</code> function is used to dispatch actions (<code>{ type: 'INCREMENT' }</code> and <code>{ type: 'DECREMENT' }</code>) to update the state.</li>
<li>Each dispatched action triggers the corresponding case in the reducer, updating the state as defined.</li>
</ul>
<h3 id="heading-dispatching-actions-from-components-or-events">Dispatching Actions from Components or Events</h3>
<p>In a typical Redux application, actions are often dispatched from React components in response to user interactions or other events. </p>
<p>To dispatch actions from components, you typically connect the component to the Redux store using React Redux's <code>connect</code> function or hooks like <code>useDispatch</code>.</p>
<p>Here's how you can dispatch actions from a React component using <code>connect</code> and <code>mapDispatchToProps</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> { connect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;

<span class="hljs-comment">// Action creator functions</span>
<span class="hljs-keyword">const</span> increment = <span class="hljs-function">() =&gt;</span> ({ <span class="hljs-attr">type</span>: <span class="hljs-string">'INCREMENT'</span> });
<span class="hljs-keyword">const</span> decrement = <span class="hljs-function">() =&gt;</span> ({ <span class="hljs-attr">type</span>: <span class="hljs-string">'DECREMENT'</span> });

<span class="hljs-comment">// Component definition</span>
<span class="hljs-keyword">const</span> Counter = <span class="hljs-function">(<span class="hljs-params">{ count, increment, decrement }</span>) =&gt;</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>Count: {count}<span class="hljs-tag">&lt;/<span class="hljs-name">p</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-comment">// Map state to props</span>
<span class="hljs-keyword">const</span> mapStateToProps = <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> ({
  <span class="hljs-attr">count</span>: state.count
});

<span class="hljs-comment">// Map dispatch to props</span>
<span class="hljs-keyword">const</span> mapDispatchToProps = {
  increment,
  decrement
};

<span class="hljs-comment">// Connect component to Redux store</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> connect(mapStateToProps, mapDispatchToProps)(Counter);
</code></pre>
<p>In this example:</p>
<ul>
<li><code>increment</code> and <code>decrement</code> are action creator functions that return actions (<code>{ type: 'INCREMENT' }</code> and <code>{ type: 'DECREMENT' }</code>).</li>
<li>The <code>Counter</code> component is connected to the Redux store using <code>connect</code>. It receives <code>count</code> from the Redux state as a prop, along with <code>increment</code> and <code>decrement</code> action creators.</li>
<li>Clicking the "Increment" and "Decrement" buttons dispatches actions, which are handled by the reducer to update the Redux state.</li>
</ul>
<p>Alternatively, you can use React Redux hooks (<code>useDispatch</code>) for dispatching actions in functional components:</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> { useDispatch, useSelector } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;

<span class="hljs-keyword">const</span> Counter = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> count = useSelector(<span class="hljs-function"><span class="hljs-params">state</span> =&gt;</span> state.count);
  <span class="hljs-keyword">const</span> dispatch = useDispatch();

  <span class="hljs-keyword">const</span> handleIncrement = <span class="hljs-function">() =&gt;</span> {
    dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">'INCREMENT'</span> });
  };

  <span class="hljs-keyword">const</span> handleDecrement = <span class="hljs-function">() =&gt;</span> {
    dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">'DECREMENT'</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>Count: {count}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleIncrement}</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">{handleDecrement}</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>In this functional component example:</p>
<ul>
<li><code>useSelector</code> is used to select <code>count</code> from the Redux store state.</li>
<li><code>useDispatch</code> is used to get the <code>dispatch</code> function from the Redux store.</li>
<li><code>handleIncrement</code> and <code>handleDecrement</code> functions dispatch actions (<code>{ type: 'INCREMENT' }</code> and <code>{ type: 'DECREMENT' }</code>) to update the Redux state when the buttons are clicked.</li>
</ul>
<h2 id="heading-how-to-access-specific-data-from-the-store">How to Access Specific Data from the Store</h2>
<p>Accessing specific data from the store in Redux involves navigating through the application's state structure to retrieve precise information needed for rendering components or performing logic.</p>
<h3 id="heading-creating-selector-functions">Creating Selector Functions</h3>
<p>Selectors in Redux are functions that encapsulate the logic for retrieving specific pieces of data from the Redux store state. They help to decouple the components from the structure of the state and facilitate efficient data access and transformation.</p>
<p>Here’s how you can create selector functions:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Example Redux state</span>
<span class="hljs-keyword">const</span> initialState = {
  <span class="hljs-attr">todos</span>: [
    { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'Learn Redux'</span>, <span class="hljs-attr">completed</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">'Write Redux selectors'</span>, <span class="hljs-attr">completed</span>: <span class="hljs-literal">true</span> },
    <span class="hljs-comment">// more todos...</span>
  ],
  <span class="hljs-attr">visibilityFilter</span>: <span class="hljs-string">'SHOW_COMPLETED'</span>
};

<span class="hljs-comment">// Selector function to get todos from state</span>
<span class="hljs-keyword">const</span> getTodos = <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.todos;

<span class="hljs-comment">// Selector function to filter todos based on visibility filter</span>
<span class="hljs-keyword">const</span> getVisibleTodos = <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> todos = getTodos(state);
  <span class="hljs-keyword">const</span> visibilityFilter = state.visibilityFilter;

  <span class="hljs-keyword">switch</span> (visibilityFilter) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'SHOW_COMPLETED'</span>:
      <span class="hljs-keyword">return</span> todos.filter(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> todo.completed);
    <span class="hljs-keyword">case</span> <span class="hljs-string">'SHOW_ACTIVE'</span>:
      <span class="hljs-keyword">return</span> todos.filter(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> !todo.completed);
    <span class="hljs-keyword">case</span> <span class="hljs-string">'SHOW_ALL'</span>:
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> todos;
  }
};
</code></pre>
<p>In this example:</p>
<ul>
<li><code>getTodos</code> is a selector function that retrieves the <code>todos</code> array from the Redux state.</li>
<li><code>getVisibleTodos</code> is a selector function that filters <code>todos</code> based on the <code>visibilityFilter</code> stored in the state.</li>
</ul>
<p>Selectors can also be composed to create more complex selectors:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Composed selector function to get visible todos</span>
<span class="hljs-keyword">const</span> getVisibleTodos = <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> todos = getTodos(state);
  <span class="hljs-keyword">const</span> visibilityFilter = state.visibilityFilter;

  <span class="hljs-keyword">switch</span> (visibilityFilter) {
    <span class="hljs-keyword">case</span> <span class="hljs-string">'SHOW_COMPLETED'</span>:
      <span class="hljs-keyword">return</span> getCompletedTodos(todos);
    <span class="hljs-keyword">case</span> <span class="hljs-string">'SHOW_ACTIVE'</span>:
      <span class="hljs-keyword">return</span> getActiveTodos(todos);
    <span class="hljs-keyword">case</span> <span class="hljs-string">'SHOW_ALL'</span>:
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> todos;
  }
};

<span class="hljs-comment">// Helper functions for filtering todos</span>
<span class="hljs-keyword">const</span> getCompletedTodos = <span class="hljs-function">(<span class="hljs-params">todos</span>) =&gt;</span> todos.filter(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> todo.completed);
<span class="hljs-keyword">const</span> getActiveTodos = <span class="hljs-function">(<span class="hljs-params">todos</span>) =&gt;</span> todos.filter(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> !todo.completed);
</code></pre>
<h3 id="heading-memoization-for-efficient-selector-usage">Memoization for Efficient Selector Usage</h3>
<p>Memoization is a technique used to optimize expensive computations by caching the results of function calls based on their input. In the context of Redux selectors, memoization can improve performance by ensuring that selectors only recalculate their results when their input (state) changes.</p>
<p>You can use libraries like <code>reselect</code> for memoization in Redux selectors:</p>
<pre><code class="lang-bash">npm install reselect
</code></pre>
<p>Example usage of <code>reselect</code> for memoization:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createSelector } <span class="hljs-keyword">from</span> <span class="hljs-string">'reselect'</span>;

<span class="hljs-comment">// Selectors</span>
<span class="hljs-keyword">const</span> getTodos = <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.todos;
<span class="hljs-keyword">const</span> getVisibilityFilter = <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> state.visibilityFilter;

<span class="hljs-comment">// Memoized selector to get visible todos</span>
<span class="hljs-keyword">const</span> getVisibleTodos = createSelector(
  [getTodos, getVisibilityFilter],
  <span class="hljs-function">(<span class="hljs-params">todos, visibilityFilter</span>) =&gt;</span> {
    <span class="hljs-keyword">switch</span> (visibilityFilter) {
      <span class="hljs-keyword">case</span> <span class="hljs-string">'SHOW_COMPLETED'</span>:
        <span class="hljs-keyword">return</span> todos.filter(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> todo.completed);
      <span class="hljs-keyword">case</span> <span class="hljs-string">'SHOW_ACTIVE'</span>:
        <span class="hljs-keyword">return</span> todos.filter(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span> !todo.completed);
      <span class="hljs-keyword">case</span> <span class="hljs-string">'SHOW_ALL'</span>:
      <span class="hljs-keyword">default</span>:
        <span class="hljs-keyword">return</span> todos;
    }
  }
);
</code></pre>
<p>In this example:</p>
<ul>
<li><code>createSelector</code> from <code>reselect</code> creates a memoized selector that takes <code>getTodos</code> and <code>getVisibilityFilter</code> as input selectors.</li>
<li>The selector function computes the filtered todos based on the <code>visibilityFilter</code> and caches the result until the input selectors change.</li>
</ul>
<h2 id="heading-how-to-connect-react-components-to-redux">How to Connect React Components to Redux</h2>
<p>Connecting React components to Redux is a fundamental technique for managing application state efficiently within React-based projects. Redux serves as a centralized store that holds the entire state of your application, making it accessible to any component that needs it.</p>
<h3 id="heading-the-connect-function-from-react-redux-library">The <code>connect</code> Function from react-redux Library</h3>
<p>In React applications using Redux for state management, the <code>connect</code> function from the <code>react-redux</code> library is used to connect React components to the Redux store. It provides a way to inject Redux state and action dispatching functions (dispatchers) into your components.</p>
<p>Here’s how you use <code>connect</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> { connect } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;

<span class="hljs-comment">// Define a React component</span>
<span class="hljs-keyword">const</span> Counter = <span class="hljs-function">(<span class="hljs-params">{ count, increment, decrement }</span>) =&gt;</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>Count: {count}<span class="hljs-tag">&lt;/<span class="hljs-name">p</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-comment">// Map Redux state to component props</span>
<span class="hljs-keyword">const</span> mapStateToProps = <span class="hljs-function">(<span class="hljs-params">state</span>) =&gt;</span> ({
  <span class="hljs-attr">count</span>: state.count
});

<span class="hljs-comment">// Map dispatching actions to component props</span>
<span class="hljs-keyword">const</span> mapDispatchToProps = {
  <span class="hljs-attr">increment</span>: <span class="hljs-function">() =&gt;</span> ({ <span class="hljs-attr">type</span>: <span class="hljs-string">'INCREMENT'</span> }),
  <span class="hljs-attr">decrement</span>: <span class="hljs-function">() =&gt;</span> ({ <span class="hljs-attr">type</span>: <span class="hljs-string">'DECREMENT'</span> })
};

<span class="hljs-comment">// Connect component to Redux store</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> connect(mapStateToProps, mapDispatchToProps)(Counter);
</code></pre>
<h3 id="heading-mapping-state-and-dispatch-to-props">Mapping State and Dispatch to Props</h3>
<p><strong><code>mapStateToProps</code></strong>: This function maps the Redux store's state to the props of your React component. It takes the Redux state as an argument and returns an object. Each field in the returned object will become a prop for the connected component.</p>
<p><strong><code>mapDispatchToProps</code></strong>: This function maps dispatching actions to props of your React component. It can be an object where each field is an action creator function, or a function that receives <code>dispatch</code> as an argument and returns an object. Each action creator will be wrapped automatically with <code>dispatch</code> so they can be called directly.</p>
<p>In the example:</p>
<ul>
<li><code>mapStateToProps</code> maps the <code>count</code> field from the Redux state (<code>state.count</code>) to the <code>count</code> prop of the <code>Counter</code> component.</li>
<li><code>mapDispatchToProps</code> maps the <code>increment</code> and <code>decrement</code> actions to props, so clicking the buttons in the <code>Counter</code> component will dispatch the corresponding actions (<code>{ type: 'INCREMENT' }</code> and <code>{ type: 'DECREMENT' }</code>).</li>
</ul>
<h3 id="heading-using-connected-components-in-your-application">Using Connected Components in Your Application</h3>
<p>Once a component is connected to the Redux store using <code>connect</code>, it can access Redux state and dispatch actions via props. Here’s how you can use connected components in your application:</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'</span>;
<span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;
<span class="hljs-keyword">import</span> { createStore } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>;
<span class="hljs-keyword">import</span> rootReducer <span class="hljs-keyword">from</span> <span class="hljs-string">'./reducers'</span>; <span class="hljs-comment">// Import your root reducer</span>
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>; <span class="hljs-comment">// Import your connected component</span>

<span class="hljs-comment">// Create Redux store with root reducer</span>
<span class="hljs-keyword">const</span> store = createStore(rootReducer);

<span class="hljs-comment">// Render the App component inside the Provider</span>
ReactDOM.render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Provider</span> <span class="hljs-attr">store</span>=<span class="hljs-string">{store}</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">Provider</span>&gt;</span></span>,
  <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)
);
</code></pre>
<p>In this setup:</p>
<ul>
<li><code>Provider</code> is a component from <code>react-redux</code> that makes the Redux store available to any nested components that have been connected using <code>connect</code>.</li>
<li><code>store</code> is created using <code>createStore</code> and combined with a root reducer (<code>rootReducer</code>) that combines all your reducers into one.</li>
</ul>
<p>By wrapping your top-level component (<code>App</code> in this case) with <code>Provider</code> and passing the Redux store as a prop, all connected components within your application can access the Redux store and interact with it through props (<code>mapStateToProps</code> and <code>mapDispatchToProps</code> mappings).</p>
<h2 id="heading-advanced-redux-data-flow-techniques">Advanced Redux Data Flow Techniques</h2>
<p>Advanced Redux data flow techniques expand upon the fundamental principles of managing state in complex applications. These techniques go beyond basic actions and reducers, introducing concepts such as middleware, selectors, and asynchronous actions.</p>
<h3 id="heading-asynchronous-actions-redux-thunk-redux-saga">Asynchronous Actions (Redux Thunk, Redux Saga)</h3>
<p>In Redux, handling asynchronous actions involves managing actions that have side effects, such as fetching data from a server or updating state asynchronously. Redux provides several middleware solutions to handle asynchronous actions effectively.</p>
<h4 id="heading-redux-thunk">Redux Thunk</h4>
<p>Redux Thunk is a middleware that allows you to write action creators that return a function instead of an action object. This function can then perform asynchronous operations and dispatch regular synchronous actions when the asynchronous operations complete.</p>
<p>Example of using Redux Thunk for asynchronous actions:</p>
<p><strong>Setting up Redux Thunk Middleware</strong>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createStore, applyMiddleware } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>;
<span class="hljs-keyword">import</span> thunk <span class="hljs-keyword">from</span> <span class="hljs-string">'redux-thunk'</span>;
<span class="hljs-keyword">import</span> rootReducer <span class="hljs-keyword">from</span> <span class="hljs-string">'./reducers'</span>; <span class="hljs-comment">// Import your root reducer</span>

<span class="hljs-comment">// Create Redux store with thunk middleware</span>
<span class="hljs-keyword">const</span> store = createStore(rootReducer, applyMiddleware(thunk));
</code></pre>
<p><strong>Async Action Creator using Redux Thunk</strong>:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Action creator function using Redux Thunk</span>
<span class="hljs-keyword">const</span> fetchPosts = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">async</span> (dispatch) =&gt; {
    dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">'FETCH_POSTS_REQUEST'</span> });

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/posts'</span>);
      <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> response.json();
      dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">'FETCH_POSTS_SUCCESS'</span>, <span class="hljs-attr">payload</span>: posts });
    } <span class="hljs-keyword">catch</span> (error) {
      dispatch({ <span class="hljs-attr">type</span>: <span class="hljs-string">'FETCH_POSTS_FAILURE'</span>, <span class="hljs-attr">error</span>: error.message });
    }
  };
};
</code></pre>
<p>In this example:</p>
<ul>
<li><code>fetchPosts</code> is an action creator that returns a function instead of an action object.</li>
<li>Inside the function, you can perform asynchronous operations (like fetching data) and dispatch actions based on the result.</li>
<li>Redux Thunk middleware intercepts functions returned by action creators, enabling asynchronous actions in Redux.</li>
</ul>
<h4 id="heading-redux-saga">Redux Saga</h4>
<p>Redux Saga is another middleware for handling side effects in Redux applications. It uses ES6 generators to make asynchronous code easier to read, write, and test.</p>
<p>Example of using Redux Saga for handling asynchronous actions:</p>
<p><strong>Setting up Redux Saga Middleware</strong>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { createStore, applyMiddleware } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>;
<span class="hljs-keyword">import</span> createSagaMiddleware <span class="hljs-keyword">from</span> <span class="hljs-string">'redux-saga'</span>;
<span class="hljs-keyword">import</span> rootReducer <span class="hljs-keyword">from</span> <span class="hljs-string">'./reducers'</span>; <span class="hljs-comment">// Import your root reducer</span>
<span class="hljs-keyword">import</span> rootSaga <span class="hljs-keyword">from</span> <span class="hljs-string">'./sagas'</span>; <span class="hljs-comment">// Import your root saga</span>

<span class="hljs-comment">// Create Redux Saga middleware</span>
<span class="hljs-keyword">const</span> sagaMiddleware = createSagaMiddleware();

<span class="hljs-comment">// Create Redux store with Saga middleware</span>
<span class="hljs-keyword">const</span> store = createStore(rootReducer, applyMiddleware(sagaMiddleware));

<span class="hljs-comment">// Run the root saga</span>
sagaMiddleware.run(rootSaga);
</code></pre>
<p><strong>Example Saga (rootSaga.js)</strong>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { all, call, put, takeEvery } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux-saga/effects'</span>;
<span class="hljs-keyword">import</span> { fetchPostsSuccess, fetchPostsFailure } <span class="hljs-keyword">from</span> <span class="hljs-string">'./actions'</span>; <span class="hljs-comment">// Import your action creators</span>

<span class="hljs-comment">// Worker saga for fetching posts</span>
<span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">fetchPostsSaga</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">yield</span> call(fetch, <span class="hljs-string">'https://jsonplaceholder.typicode.com/posts'</span>);
    <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">yield</span> call([response, <span class="hljs-string">'json'</span>]);
    <span class="hljs-keyword">yield</span> put(fetchPostsSuccess(posts));
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">yield</span> put(fetchPostsFailure(error.message));
  }
}

<span class="hljs-comment">// Watcher saga to listen for FETCH_POSTS_REQUEST action</span>
<span class="hljs-function"><span class="hljs-keyword">function</span>* <span class="hljs-title">watchFetchPosts</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">yield</span> takeEvery(<span class="hljs-string">'FETCH_POSTS_REQUEST'</span>, fetchPostsSaga);
}

<span class="hljs-comment">// Root saga</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">rootSaga</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">yield</span> all([
    watchFetchPosts()
    <span class="hljs-comment">// Add more watchers if needed</span>
  ]);
}
</code></pre>
<p>In this example:</p>
<ul>
<li><code>fetchPostsSaga</code> is a worker saga that performs the asynchronous operation (fetching posts).</li>
<li><code>watchFetchPosts</code> is a watcher saga that listens for specific actions (<code>FETCH_POSTS_REQUEST</code>) and triggers the corresponding worker saga.</li>
<li><code>rootSaga</code> combines multiple sagas using <code>all</code> and runs them using <code>sagaMiddleware.run</code>.</li>
</ul>
<h3 id="heading-middleware-for-extending-redux-functionality">Middleware for Extending Redux Functionality</h3>
<p>Middleware in Redux provides a way to extend the Redux store's capabilities, such as logging actions, handling asynchronous operations, routing, and more. Middleware sits between dispatching an action and the moment it reaches the reducer, allowing interception and manipulation of actions.</p>
<h4 id="heading-example-of-custom-middleware">Example of Custom Middleware:</h4>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> loggerMiddleware = <span class="hljs-function"><span class="hljs-params">store</span> =&gt;</span> <span class="hljs-function"><span class="hljs-params">next</span> =&gt;</span> <span class="hljs-function"><span class="hljs-params">action</span> =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Dispatching action:'</span>, action);
  <span class="hljs-keyword">const</span> result = next(action);
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'New state:'</span>, store.getState());
  <span class="hljs-keyword">return</span> result;
};

<span class="hljs-comment">// Applying custom middleware to Redux store</span>
<span class="hljs-keyword">import</span> { createStore, applyMiddleware } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>;
<span class="hljs-keyword">import</span> rootReducer <span class="hljs-keyword">from</span> <span class="hljs-string">'./reducers'</span>; <span class="hljs-comment">// Import your root reducer</span>

<span class="hljs-comment">// Create Redux store with custom middleware</span>
<span class="hljs-keyword">const</span> store = createStore(rootReducer, applyMiddleware(loggerMiddleware));
</code></pre>
<p>In this example:</p>
<ul>
<li><code>loggerMiddleware</code> is a custom middleware function that logs each dispatched action and the resulting state.</li>
<li><code>next</code> is a function provided by Redux that allows the action to continue to the next middleware or the reducer.</li>
<li>Custom middleware enhances Redux functionality by intercepting actions, performing custom logic, and optionally dispatching new actions or modifying existing ones.</li>
</ul>
<h2 id="heading-best-practices-for-managing-data-flow-in-redux">Best Practices for Managing Data Flow in Redux</h2>
<p>Redux provides a structured way to manage state in JavaScript applications, but effective usage requires adhering to best practices. Here are my key recommendations for managing data flow in Redux:</p>
<h3 id="heading-organizing-reducers-and-actions">Organizing Reducers and Actions</h3>
<p><strong>File Structure and Organization</strong>:</p>
<ul>
<li><strong>Separate concerns</strong>: Keep actions, reducers, and selectors in separate files to maintain clarity and modularity.</li>
<li><strong>Feature-based structure</strong>: Group related actions and reducers together based on features rather than types.</li>
</ul>
<pre><code class="lang-plaintext">src/
├── actions/
│   ├── todosActions.js
│   └── userActions.js
├── reducers/
│   ├── todosReducer.js
│   └── userReducer.js
├── selectors/
│   ├── todosSelectors.js
│   └── userSelectors.js
└── store.js
</code></pre>
<p><strong>Action Types</strong>:</p>
<ul>
<li><strong>Constants</strong>: Use constants or enums for action types to prevent typos and ensure consistency.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-comment">// Action types</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ADD_TODO = <span class="hljs-string">'ADD_TODO'</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> DELETE_TODO = <span class="hljs-string">'DELETE_TODO'</span>;
</code></pre>
<p><strong>Reducer Composition</strong>:</p>
<ul>
<li><strong>Combine reducers</strong>: Use <code>combineReducers</code> from Redux to combine multiple reducers into a single root reducer.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { combineReducers } <span class="hljs-keyword">from</span> <span class="hljs-string">'redux'</span>;
<span class="hljs-keyword">import</span> todosReducer <span class="hljs-keyword">from</span> <span class="hljs-string">'./todosReducer'</span>;
<span class="hljs-keyword">import</span> userReducer <span class="hljs-keyword">from</span> <span class="hljs-string">'./userReducer'</span>;

<span class="hljs-keyword">const</span> rootReducer = combineReducers({
  <span class="hljs-attr">todos</span>: todosReducer,
  <span class="hljs-attr">user</span>: userReducer
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> rootReducer;
</code></pre>
<h3 id="heading-immutable-state-updates">Immutable State Updates</h3>
<p><strong>Immutability with Spread Operator</strong>:</p>
<ul>
<li><strong>Use spread operator (<code>...</code>)</strong>: Create new objects or arrays when updating state to maintain immutability.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-comment">// Updating an array in Redux state</span>
<span class="hljs-keyword">const</span> todosReducer = <span class="hljs-function">(<span class="hljs-params">state = initialState, action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> ADD_TODO:
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">todos</span>: [
          ...state.todos,
          {
            <span class="hljs-attr">id</span>: action.id,
            <span class="hljs-attr">text</span>: action.text,
            <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>
          }
        ]
      };
    <span class="hljs-keyword">case</span> TOGGLE_TODO:
      <span class="hljs-keyword">return</span> {
        ...state,
        <span class="hljs-attr">todos</span>: state.todos.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span>
          (todo.id === action.id) ? { ...todo, <span class="hljs-attr">completed</span>: !todo.completed } : todo
        )
      };
    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state;
  }
};
</code></pre>
<p><strong>Immutable Libraries</strong>:</p>
<ul>
<li><strong>Immutable.js</strong>: Consider using libraries like Immutable.js for more complex data structures to enforce immutability and optimize performance.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { <span class="hljs-built_in">Map</span>, List } <span class="hljs-keyword">from</span> <span class="hljs-string">'immutable'</span>;

<span class="hljs-keyword">const</span> initialState = <span class="hljs-built_in">Map</span>({
  <span class="hljs-attr">todos</span>: List(),
  <span class="hljs-attr">user</span>: <span class="hljs-built_in">Map</span>()
});

<span class="hljs-keyword">const</span> todosReducer = <span class="hljs-function">(<span class="hljs-params">state = initialState, action</span>) =&gt;</span> {
  <span class="hljs-keyword">switch</span> (action.type) {
    <span class="hljs-keyword">case</span> ADD_TODO:
      <span class="hljs-keyword">return</span> state.update(<span class="hljs-string">'todos'</span>, <span class="hljs-function"><span class="hljs-params">todos</span> =&gt;</span> todos.push(<span class="hljs-built_in">Map</span>({
        <span class="hljs-attr">id</span>: action.id,
        <span class="hljs-attr">text</span>: action.text,
        <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>
      })));

    <span class="hljs-keyword">case</span> TOGGLE_TODO:
      <span class="hljs-keyword">return</span> state.update(<span class="hljs-string">'todos'</span>, <span class="hljs-function"><span class="hljs-params">todos</span> =&gt;</span>
        todos.map(<span class="hljs-function"><span class="hljs-params">todo</span> =&gt;</span>
          (todo.get(<span class="hljs-string">'id'</span>) === action.id) ? todo.set(<span class="hljs-string">'completed'</span>, !todo.get(<span class="hljs-string">'completed'</span>)) : todo
        )
      );

    <span class="hljs-keyword">default</span>:
      <span class="hljs-keyword">return</span> state;
  }
};
</code></pre>
<h3 id="heading-testing-redux-applications">Testing Redux Applications</h3>
<p><strong>Unit Testing</strong>:</p>
<ul>
<li><strong>Reducers</strong>: Test reducers to ensure they handle actions correctly and return the expected state.</li>
</ul>
<pre><code class="lang-javascript">describe(<span class="hljs-string">'todosReducer'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'should handle ADD_TODO'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> action = { <span class="hljs-attr">type</span>: <span class="hljs-string">'ADD_TODO'</span>, <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'Test todo'</span> };
    <span class="hljs-keyword">const</span> initialState = { <span class="hljs-attr">todos</span>: [] };
    <span class="hljs-keyword">const</span> expectedState = { <span class="hljs-attr">todos</span>: [{ <span class="hljs-attr">id</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">'Test todo'</span>, <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span> }] };

    expect(todosReducer(initialState, action)).toEqual(expectedState);
  });
});
</code></pre>
<p><strong>Integration Testing</strong>:</p>
<ul>
<li><strong>Action Creators and Thunks</strong>: Test action creators and thunks to verify they dispatch the correct actions or handle asynchronous operations.</li>
</ul>
<pre><code class="lang-javascript">describe(<span class="hljs-string">'fetchPosts action creator'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'creates FETCH_POSTS_SUCCESS when fetching posts has been done'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> expectedActions = [
      { <span class="hljs-attr">type</span>: <span class="hljs-string">'FETCH_POSTS_REQUEST'</span> },
      { <span class="hljs-attr">type</span>: <span class="hljs-string">'FETCH_POSTS_SUCCESS'</span>, <span class="hljs-attr">payload</span>: { <span class="hljs-comment">/* mocked data */</span> } }
    ];

    <span class="hljs-keyword">const</span> store = mockStore({ <span class="hljs-attr">posts</span>: [] });

    <span class="hljs-keyword">return</span> store.dispatch(fetchPosts()).then(<span class="hljs-function">() =&gt;</span> {
      expect(store.getActions()).toEqual(expectedActions);
    });
  });
});
</code></pre>
<p><strong>Integration with Components</strong>:</p>
<ul>
<li><strong>Connected Components</strong>: Test connected components using <code>redux-mock-store</code> to simulate Redux store behavior.</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> configureStore <span class="hljs-keyword">from</span> <span class="hljs-string">'redux-mock-store'</span>;
<span class="hljs-keyword">import</span> { Provider } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-redux'</span>;
<span class="hljs-keyword">import</span> { render } <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App'</span>;

<span class="hljs-keyword">const</span> mockStore = configureStore([]);

describe(<span class="hljs-string">'&lt;App /&gt;'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'renders App component'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> store = mockStore({ <span class="hljs-comment">/* mocked state */</span> });

    <span class="hljs-keyword">const</span> { getByText } = render(
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Provider</span> <span class="hljs-attr">store</span>=<span class="hljs-string">{store}</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">Provider</span>&gt;</span></span>
    );

    expect(getByText(<span class="hljs-string">'Welcome to Redux App'</span>)).toBeInTheDocument();
  });
});
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Redux offers a powerful state management solution for JavaScript applications, providing a predictable and centralized way to manage application state. </p>
<p>Whether handling asynchronous operations with middleware like Redux Thunk or Redux Saga, or optimizing state management through immutable data practices, Redux empowers you to build scalable and maintainable applications. </p>
<p>By mastering these techniques, you can leverage Redux to streamline data flow, enhance application performance, and simplify the complexities of managing state in modern web development.</p>
<p>That's all for this article! If you'd like to continue the conversation or have questions, suggestions, or feedback, feel free to reach out to connect with me on <a target="_blank" href="https://ng.linkedin.com/in/joan-ayebola">LinkedIn</a>. And if you enjoyed this content, consider <a target="_blank" href="https://www.buymeacoffee.com/joanayebola">buying me a coffee</a> to support the creation of more developer-friendly contents.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ React 19 Actions – How to Simplify Form Submission and Loading States ]]>
                </title>
                <description>
                    <![CDATA[ React 19 introduces Actions, which are asynchronous functions. Actions are helpful in making form submissions easier. This tutorial dives into what Actions are and how to use them. You'll learn about: The new React 19 feature, Actions The new React ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/react-19-actions-simpliy-form-submission-and-loading-states/</link>
                <guid isPermaLink="false">66b99d04489480391dfe7a4d</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Shruti Kapoor ]]>
                </dc:creator>
                <pubDate>Tue, 02 Jul 2024 21:29:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/React--1-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>React 19 introduces Actions, which are asynchronous functions. Actions are helpful in making form submissions easier. This tutorial dives into what Actions are and how to use them.</p>
<p>You'll learn about:</p>
<ol>
<li>The new React 19 feature, Actions</li>
<li>The new React 19 hooks, <code>useActionState</code> and <code>useFormStatus</code></li>
<li>How to convert a React 18 form to a React 19 form</li>
</ol>
<p>I also made a <a target="_blank" href="https://www.youtube.com/watch?v=ExZUdkfu-KE&amp;t=443s">video version of this article</a> if you'd like to learn from that as well.</p>
<h2 id="heading-feature-react-actions">Feature: React Actions</h2>
<p>To understand Actions, let's first take a look at how we manage forms today. In React 18 and earlier, we submit forms using the <code>handleSubmit</code> function in a button. Here's a simple form that has one input field <code>name</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// Form submission in React 18</span>
<span class="hljs-built_in">console</span>.info(<span class="hljs-string">'React 18 form'</span>);

<span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>);
<span class="hljs-keyword">const</span> [isPending, setIsPending] = useState(<span class="hljs-literal">false</span>);

<span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  setName(event.target.value);
};

<span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.preventDefault();
  setIsPending(<span class="hljs-literal">true</span>);
  <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// call API</span>
    setIsPending(<span class="hljs-literal">false</span>);
  }, <span class="hljs-number">500</span>);
};

<span class="hljs-keyword">return</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</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">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span> /&gt;</span>
    {isPending ? <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">p</span>&gt;</span>Hello in React 18, {name}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>}
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSubmit}</span> <span class="hljs-attr">disabled</span>=<span class="hljs-string">{isPending}</span>&gt;</span>
      Update
    <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>In this code, we are doing the following:</p>
<ol>
<li>Adding a loading state: We use a variable <code>isPending</code> to manually keep track of the loading state.</li>
<li>Form submission: The form is submitted using the <code>handleSubmit</code> event handler attached to the <code>onClick</code> event of the button.</li>
<li>Capturing the submitted value: The <code>handleChange</code> function captures the submitted value and stores it in state variables.</li>
</ol>
<h2 id="heading-what-are-react-actions">What Are React Actions?</h2>
<p>With React 19, handling forms becomes easier with Actions, inspired by frameworks such as Remix. One key feature is the enhanced use of <code>startTransition</code> to manage pending states.</p>
<p><code>startTransition</code> was introduced in React 18, allowing developers to mark certain updates as less urgent. </p>
<p>In React 19, <code>startTransition</code> can now handle async functions, making it even more powerful for managing asynchronous tasks and improving the user experience during form submissions.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [isPending, startTransition] = useTransition();

<span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">() =&gt;</span> {
  startTransition(<span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> error = <span class="hljs-keyword">await</span> updateName(name);
    <span class="hljs-keyword">if</span> (error) {
      setError(error);
      <span class="hljs-keyword">return</span>;
    }
    redirect(<span class="hljs-string">'/path'</span>);
  });
};
</code></pre>
<p>This async function inside <code>startTransition</code> is called an Action. What makes actions cool is that they can be used directly to submit forms like so:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"{actionFn}"</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>This format may look familiar if you are experienced with PHP.</p>
<h2 id="heading-how-to-create-a-react-action">How to Create a React Action</h2>
<p>To create an async function, we can use a new hook introduced in React 19 called <code>useActionState</code>. We call this hook and pass in an action function and an initial state. This hook returns the updated state and a form action <code>actionFn</code>, which can be used to wire up a form.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [state, actionFn] = useActionState(submitAction, { <span class="hljs-attr">name</span>: <span class="hljs-string">''</span> });
</code></pre>
<p>Now with this wired up with the form, we have the following:</p>
<pre><code class="lang-jsx">&lt;form action={actionFn}&gt;
  <span class="xml"><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">name</span>=<span class="hljs-string">"name"</span> /&gt;</span></span>

  <span class="xml"><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">"{pending}"</span>&gt;</span>
    Update
  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
&lt;/form&gt;
</code></pre>
<p>To add a loading state, we can use a new hook introduced in React 19 called <code>useFormStatus</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { pending, data, method, action } = useFormStatus();
</code></pre>
<p>This hook provides information on the status of the form. The <code>pending</code> state indicates whether the form is being submitted, and <code>data</code> is a <code>FormData</code> object containing the submitted data. We use this pending state to show a loader.</p>
<p>But there is one caveat: this hook can only be used in a child component, not in the form itself. So, we have to create child components <code>SubmitButton</code> and <code>Loader</code> to retrieve a <code>pending</code> state:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Loader</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { pending } = useFormStatus();
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{pending &amp;&amp; "Loading..."}<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">SubmitButton</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { pending } = useFormStatus();
  <span class="hljs-keyword">return</span> (
    <span class="xml"><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">{pending}</span>&gt;</span>
      Update
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  );
}

....

return(
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">{formAction}</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">name</span>=<span class="hljs-string">"name"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Loader</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">SubmitButton</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
)
</code></pre>
<p>We can also capture useful information about the data submitted to the form by retrieving it from the state returned from <code>useActionState</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [state, formAction] = useActionState(submitAction, { <span class="hljs-attr">name</span>: <span class="hljs-string">''</span> });
</code></pre>
<p>So here's the final form:</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Loader</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { pending } = useFormStatus();
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>{pending &amp;&amp; 'Loading...'}<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">SubmitButton</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> { pending } = useFormStatus();
  <span class="hljs-keyword">return</span> (
    <span class="xml"><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">{pending}</span>&gt;</span>
      Update
    <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
  );
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Name</span>(<span class="hljs-params">{ name }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Hello in 19 {name}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></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-built_in">console</span>.info(<span class="hljs-string">'React 19 form'</span>);

  <span class="hljs-keyword">const</span> [state, formAction] = useActionState(submitAction, { <span class="hljs-attr">name</span>: <span class="hljs-string">''</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">{formAction}</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">name</span>=<span class="hljs-string">"name"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Loader</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">SubmitButton</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Name</span> <span class="hljs-attr">name</span>=<span class="hljs-string">{state?.name}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
</code></pre>
<p>Compare this with the React 18 form at the top of this post to check the difference.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By utilizing actions along with hooks like <code>useActionState</code> and <code>useFormStatus</code>, we can easily manage form states, capture submitted data, and provide responsive feedback to users during form submissions to show pending states. </p>
<p>I am excited for this improved experience of handling forms in React 19, and I look forward to removing unnecessary <code>handleSubmits</code>, <code>useState</code>s, and <code>pending</code> states.</p>
<p>In my next article, I will discuss another exciting new React feature: the React Compiler. This tool automatically memoizes, eliminating the need for <code>useMemo</code> and <code>useCallback</code>. Stay updated and get the article directly in your inbox by joining my newsletter.</p>
<div class="embed-wrapper"><iframe src="https://shrutikapoor.substack.com/embed" width="480" height="320" style="border:1px solid #EEE;background:white" title="Embedded content" loading="lazy"></iframe></div>

 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Infinite Scrolling in React Using the Intersection Observer API ]]>
                </title>
                <description>
                    <![CDATA[ Hi fellow developers! Have you ever wondered how social media apps like Facebook and Instagram keep you scrolling endlessly through your feed? This user experience, designed to load new content on demand, uses a technique called infinite scrolling. T... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/infinite-scrolling-in-react/</link>
                <guid isPermaLink="false">66d85155bfb3c4f0b376afec</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kunal Nalawade ]]>
                </dc:creator>
                <pubDate>Mon, 01 Jul 2024 09:24:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/photo-1563986768494-4dee2763ff3f.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hi fellow developers! Have you ever wondered how social media apps like Facebook and Instagram keep you scrolling endlessly through your feed?</p>
<p>This user experience, designed to load new content on demand, uses a technique called infinite scrolling. This helps keep you hooked to these apps for hours.</p>
<p>Traditionally, these features would have you click "Next Page" to display new content. However, infinite scrolling reduces the load on the server by fetching less data at a time and thus, provides a much more engaging user experience.</p>
<p>In this post, we are going to implement the same feature in JavaScript. We'll use the Intersection Observer API to load data on demand, as the user is scrolling. We'll create a simple React application that displays posts similar to a social media feed.</p>
<h2 id="heading-how-to-set-up-the-react-app">How to Set Up the React App</h2>
<p>Run <code>create-react-app</code> in your terminal or use a <a target="_blank" href="https://www.freecodecamp.org/news/get-started-with-vite/">modern built tool like Vite</a> to create your React app. Remove the existing boilerplate code. There is no need to install any additional dependencies. Run <code>npm start</code> command to start the project.</p>
<p>You can find the complete code of this tutorial on <a target="_blank" href="https://github.com/KunalN25/my-tutorials/tree/main/javascript-and-react/infinite-scroll-js">GitHub</a>. Let's get started.</p>
<h2 id="heading-how-to-create-the-data-fetching-function">How to Create the Data Fetching Function</h2>
<p>Create a separate file called <code>services.js</code> and write the following data fetching function.</p>
<p>We'll use the <code>/posts</code> API from <a target="_blank" href="https://jsonplaceholder.typicode.com">JSONPlaceholder</a> to get our data.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> fetchPosts = <span class="hljs-keyword">async</span> (page, limit) =&gt; {
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
    <span class="hljs-string">`https://jsonplaceholder.typicode.com/posts?_page=<span class="hljs-subst">${page}</span>&amp;_limit=<span class="hljs-subst">${limit}</span>`</span>
  );
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
  <span class="hljs-keyword">return</span> data;
};
</code></pre>
<p>Here, we have passed two params to the API:</p>
<ul>
<li><p><code>page</code> indicates the part of data that is called. This increases each time the user scrolls and loads new data.</p>
</li>
<li><p><code>limit</code> indicates the amount of data that is called at a time. For infinite scrolling, we call just enough data that can be displayed on a single page.</p>
</li>
</ul>
<h2 id="heading-how-to-build-the-infinite-scroll-component">How to Build the Infinite Scroll Component</h2>
<p>Let's create a component <code>PostsList</code> for displaying a list of posts with infinite scrolling.</p>
<p>Let's create our state variables, fetch the data, and display it:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> PostsList = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [posts, setPosts] = useState([]);
  <span class="hljs-keyword">const</span> [page, setPage] = useState(<span class="hljs-number">1</span>);
  <span class="hljs-keyword">const</span> [loading, setLoading] = 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>Your Feed<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>
        {posts.map((post, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">li</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{post.id}</span>
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>{post.title}<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>{post.body}<span class="hljs-tag">&lt;/<span class="hljs-name">p</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>
      {loading &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">div</span>&gt;</span></span>
  );
};
</code></pre>
<p>Here, we have defined the state variables for posts, page number and loading state. Note that the page number does not mean that we are adding pagination. It's just a parameter to load the next set of data.</p>
<p>Now, let's call our API with the current page number and set the loading states:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> loadMorePosts = <span class="hljs-keyword">async</span> () =&gt; {
    setLoading(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">const</span> newPosts = <span class="hljs-keyword">await</span> fetchPosts(page, <span class="hljs-number">10</span>);
    setPosts(<span class="hljs-function">(<span class="hljs-params">prevPosts</span>) =&gt;</span> [...prevPosts, ...newPosts]);
    setLoading(<span class="hljs-literal">false</span>);
  };

  useEffect(<span class="hljs-function">() =&gt;</span> {
    loadMorePosts();
  }, [page]);
</code></pre>
<p>Until now, we have fetched the initial 10 posts on first load of the page. We want to load more data as the user scrolls down the page.</p>
<p>Next, we'll use the Intersection Observer API to detect when additional data should be loaded.</p>
<p>Before using it, let's first understand what this API is.</p>
<h2 id="heading-what-is-the-intersection-observer-api">What is the Intersection Observer API?</h2>
<p>The Intersection Observer API is a web API that allows you to asynchronously observe changes in the intersection of a target element with an ancestor element or the viewport.</p>
<p>In simpler terms, it enables you to detect when an element enters or exits in an area of another DOM element or the viewport. Using Intersection Observer provides us with following advantages:</p>
<ul>
<li><p>Reduces the need for attaching event listeners to every scroll event.</p>
</li>
<li><p>Removes the need for manual calculations of the element's position and their event listeners, thus simplifying your code.</p>
</li>
<li><p>Efficient for observing multiple events compared to scroll or resize event listeners.</p>
</li>
</ul>
<p>Go through the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">MDN Docs</a> to understand more about Intersection Observer.</p>
<h2 id="heading-how-to-use-the-intersection-observer-api">How to Use the Intersection Observer API</h2>
<p>To use this API, we'll need to create an observer object.</p>
<p>Here's how you create an observer object:</p>
<pre><code class="lang-python">const observer = new IntersectionObserver(callback, options);
</code></pre>
<ul>
<li><p><code>callback</code> is a function called when the observed element's visibility changes. This function takes two arguments: <code>entries</code> and the <code>observer</code> object itself. Each object in <code>entries</code> array is an <code>IntersectionObserverEntry</code> object that contains information about the observed element's intersection status.</p>
</li>
<li><p><code>options</code> is an optional argument to further configure the Observer.</p>
</li>
</ul>
<p>How do we use this in our application? We'll define observer object as a ref:</p>
<pre><code class="lang-js">  <span class="hljs-keyword">const</span> observer = useRef();
</code></pre>
<p>Now, to set this observer object on an element and to detect whether that element is intersecting with the viewport, we use the following function, which is a callback ref:</p>
<pre><code class="lang-python">const lastPostElementRef = useCallback(
    (node) =&gt; {
      <span class="hljs-keyword">if</span> (loading) <span class="hljs-keyword">return</span>;
      <span class="hljs-keyword">if</span> (observer.current) observer.current.disconnect();

      observer.current = new IntersectionObserver((entries) =&gt; {
        <span class="hljs-keyword">if</span> (entries[<span class="hljs-number">0</span>].isIntersecting) {
          setPage((prevPage) =&gt; prevPage + <span class="hljs-number">1</span>); // trigger loading of new posts by chaging page no
        }
      });

      <span class="hljs-keyword">if</span> (node) observer.current.observe(node);
    },
    [loading]
  );
</code></pre>
<p>Let's understand how this function works:</p>
<ul>
<li><p>We check if the data is still loading. If it is, then we do not execute the logic.</p>
</li>
<li><p>To refer to the <code>observer</code> object, we use the ref's <code>current</code> property.</p>
</li>
<li><p>If an element is already being observed, then disconnect it and create a new Observer that changes the page number, thus triggering the API call if the observed element intersects with the viewport.</p>
</li>
<li><p>Since we are only observing one element at a time (such as the last element of the page) the size of <code>entries</code> is one.</p>
</li>
<li><p>This new Observer will now watch the current element to which the ref is attached to, which is the last element on the page.</p>
</li>
</ul>
<p>Since we only want to observe the last element on the page, we add this ref according to following condition:</p>
<pre><code class="lang-python">{posts.map((post, index) =&gt; (
          &lt;li
            key={post.id}
            ref={posts.length === index + <span class="hljs-number">1</span> ? lastPostElementRef : null}
          &gt;
            ...
          &lt;/li&gt;
        ))}
</code></pre>
<p>Now, why are we using callback refs instead of the <code>observer</code> ref itself?</p>
<p>A ref gives us a direct reference to the element and sets the value of the ref object directly. It works well for elements that do not need to change reference dynamically.</p>
<p>A callback ref offers more control over the ref and can handle dynamic changes to reference more effectively. It is a function called with the element's instance, or its DOM Node when the component mounts and with null if it unmounts.</p>
<p>In our case, our reference changes dynamically since our last element gets updated as more data is loaded. We are also able to write some logic to observe and disconnect from a node, while setting our ref object.</p>
<p>We'll also wrap the <code>lastPostElementRef</code> function inside a <code>useCallback</code> hook to avoid it getting re-created on every re-render. We'll only create this function if the loading state changes when it's time to execute the function.</p>
<p>Run your app with <code>npm start</code>, go to <code>http://localhost:3000</code>, and open the Network Tab. As you scroll down, you'll see new API requests being made as you scroll down the page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/image-101.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>API requests for each new page</em></p>
<p>You can find the complete code on <a target="_blank" href="https://github.com/KunalN25/my-tutorials/tree/main/javascript-and-react/infinite-scroll-js">GitHub</a> and similar tutorials in JavaScript and React.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>When you implement infinite scrolling in your application, it provides a seamless and engaging user experience similar to what you see on popular social media apps. Instead of clicking through pages, users can effortlessly scroll through the content that loads dynamically.</p>
<p>In our example, we created a mock social media feed that loaded more content as the user scrolls down. We used the Intersection Observer API to detect the position of the last element according to which we loaded more data. It simplified our code and removed the need for attaching multiple event listeners.</p>
<p>I hope this helps you create similar features in your next web project and enables you to provide an engaging user experience. Please share your thoughts and feedback. Thank you!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Validate Forms in React and React Native Using Yup and Formik ]]>
                </title>
                <description>
                    <![CDATA[ Validation is a key part of development, regardless of what programming language you’re writing. Developers should always be validating user input, API parameters, and retrieved values. One of the most common elements where you’ll need to apply user ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/react-how-to-validate-user-input/</link>
                <guid isPermaLink="false">66bb889bc32849d18c5cdca7</guid>
                
                    <category>
                        <![CDATA[ Form validations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ forms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Grant Riordan ]]>
                </dc:creator>
                <pubDate>Mon, 24 Jun 2024 19:51:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/1080_Template.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Validation is a key part of development, regardless of what programming language you’re writing. Developers should always be validating user input, API parameters, and retrieved values.</p>
<p>One of the most common elements where you’ll need to apply user input validation is via a form. This could be a user sign up form, a contact us form, or a simple questionnaire.</p>
<h2 id="heading-outcomes-of-the-tutorial">Outcomes of the Tutorial</h2>
<p>By the end of this article , you will be able to:</p>
<ul>
<li>Understand common issues with form validation.</li>
<li>How to utilise the Yup schema validation library alongside the Formik form library.</li>
<li>How to build a form in React with full validation (same principles apply for React Native, with different component syntax).</li>
</ul>
<h2 id="heading-contents">Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-validation">What is Validation</a>?</li>
<li><a class="post-section-overview" href="#heading-the-object-to-be-validated">The Object to Be Validated</a></li>
<li><a class="post-section-overview" href="#heading-introducing-yup-and-formik">Introducing Yup and Formik</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-validation-to-a-form">How to Add Validation to a Form</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-what-is-validation">What is Validation?</h2>
<p>Validation is defined as:</p>
<blockquote>
<p><em>the action of checking or proving the validity or accuracy of something.</em></p>
</blockquote>
<p>But what does that mean in computer speak? This could be a multitude of things, but the premise still stands. You could be validating a variable value or an object against a pre-determined set of rules or regulations.</p>
<p>Examples of validation rules could be:</p>
<ul>
<li>Password must be at least 8 characters and contain a special character.</li>
<li>Username must be unique.</li>
<li>Date of birth must be received as a string, in a particular format, for example ISO8601</li>
</ul>
<p>Let’s use the example of a user registration form on a website. </p>
<h2 id="heading-the-object-to-be-validated">The Object to Be Validated</h2>
<p>The form will comprise of several inputs to form a <code>UserRegistration</code> object. Like so‌:</p>
<pre><code class="lang-ts"><span class="hljs-keyword">interface</span> UserRegistration {
  firstName: <span class="hljs-built_in">string</span>;
  surname: <span class="hljs-built_in">string</span>;
  email: <span class="hljs-built_in">string</span>;
  dob: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>Above is an interface (contract) for a <code>UserRegistration</code> object. It simply defines some key user information which needs to be collected, with all values being a <code>string</code> value.</p>
<p>While languages like TypeScript are useful for ensuring that we pass the correct types to functions throughout our application, they do not inherently validate the actual content or values within those types. TypeScript guarantees that a variable is of a specific type, such as a string or a number, but it does not verify if the content of that string or number meets specific criteria or constraints.</p>
<h3 id="heading-what-if-we-didnt-validate-the-values">What If We Didn't Validate the Values?</h3>
<p>Ok, before we move onto how to validate, let's look at what could happen if we don't validate.</p>
<p>Without validation, a user could input the following values:</p>
<p><strong>Firstname</strong>: 1231301‌<br>‌<strong>Surname</strong>: Hello##test_101‌<br>‌<strong>Email</strong>: user_123@@email.to@.com‌<br>‌<strong>DoB</strong>: 10+12+1909</p>
<p>These values may <strong>seem</strong> perfectly acceptable, and your front end might allow them to be submitted without any issues. And the API will likely accept these values initially. </p>
<p>But when the API attempts to parse these values (converting) during the request processing, it will encounter errors and fail to process the request correctly.</p>
<p>There are several negative consequences to this approach:</p>
<ol>
<li><strong>Increased Server Load</strong>: The front end is making multiple invalid requests to the server, which unnecessarily strains the server. This extra load could have been avoided.</li>
<li><strong>Potentially Higher Costs</strong>: The cost of handling these invalid requests can increase significantly, depending on your hosting plan and server configuration. Each invalid request consumes server resources that could be used more efficiently.</li>
<li><strong>Poor User Experience (UX)</strong>: Users will likely become frustrated if they repeatedly enter details, submit the form, and then receive error messages indicating that their inputs are invalid. This can lead to a negative perception of the application.</li>
</ol>
<p>To mitigate these issues and reduce the number of invalid requests, we can implement 'client-side validation' to ensure that the data meets the required criteria before sending the API request.</p>
<h2 id="heading-introducing-yup-and-formik">Introducing Yup and Formik</h2>
<p>Yup and Formik are both libraries which you can add to any React or React Native application via npm or yarn.</p>
<p>Yup is a schema building library that allows you to build schemas for validation at runtime. It has a plethora of extension functions which can set rulesets, transform values, and return validation messages right out the box.</p>
<p>Let's take a look at an example of a Yup schema for our user form:‌</p>
<pre><code class="lang-ts"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Yup <span class="hljs-keyword">from</span> <span class="hljs-string">'yup'</span>;

<span class="hljs-comment">// If using Typescript, you can utilise a wrapper function to enforce strict typing</span>

<span class="hljs-keyword">const</span> createYupSchema = &lt;T <span class="hljs-keyword">extends</span> <span class="hljs-built_in">object</span>&gt;(schema: Yup.ObjectSchema&lt;T&gt;): Yup.ObjectSchema&lt;T&gt; =&gt; schema;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> userFormSchema = createYupSchema&lt;UserInput&gt;(
  Yup.object().shape({
    firstname: Yup.string().required(<span class="hljs-string">'First name is required'</span>),
    surname: Yup.string().required(<span class="hljs-string">'Surname is required'</span>),
    email: Yup.string().email(<span class="hljs-string">'Invalid email format'</span>).required(<span class="hljs-string">'Email is required'</span>),
    dob: Yup.string().required(<span class="hljs-string">'Date of Birth is required'</span>),
  })
);

<span class="hljs-comment">// JS Version</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> validationSchema = Yup.object({
  firstname: Yup.string().required(<span class="hljs-string">'First name is required'</span>),

  surname: Yup.string().required(<span class="hljs-string">'Surname is required'</span>),
  email: Yup.string().email(<span class="hljs-string">'Invalid email format'</span>).required(<span class="hljs-string">'Email is required'</span>),
  dob: Yup.date().required(<span class="hljs-string">'Date of Birth is required'</span>)
});
</code></pre>
<p>We're creating a Yup object (schema) which contains all of our Keys for our UserInput interface.</p>
<h3 id="heading-schema-parts">Schema Parts:</h3>
<ul>
<li>key: the key which will be used later for the name of our element (as we're using TypeScript, this needs to match the object key name).</li>
<li>ruleset: for all keys, apply a ruleset. A ruleset must start with a typing declaration, that is <code>Yup.string()</code> or <code>Yup.number()</code> and so on. You can then chain your other validation functions. </li>
</ul>
<p>Using TypeScript ensures that we match the schema type to our interface types.</p>
<p>For example, if we try and do this:</p>
<pre><code class="lang-ts">firstname: Yup.date().required();
</code></pre>
<p>it will throw a TypeScript error complaining that <code>firstname</code> cannot be validated as if it was a date, as the type of firstname is a <code>string</code>.</p>
<h3 id="heading-how-to-add-validation-to-a-form">How to Add Validation to a Form</h3>
<p>This is where our Formik library comes in and makes things much easier than validating a form and implementing error handling manually.</p>
<p>Formik is a library which encapsulates a <code>&lt;Form/&gt;</code> component. It allows us to create richer forms in React and React Native, giving us access to features like form state, error handling, validation, and processing of form submissions much more efficiently.</p>
<p>You can access a pre-built version of a UserForm utilising Yup, Formik, and React (Vite) at my GitHub <a target="_blank" href="https://github.com/grant-dot-dev/fcc-yup-schema-validation">here</a>. Simply clone the GitHub repository and follow the README.md instructions. ‌</p>
<pre><code class="lang-tsx">&lt;Formik
        initialValues={initialValues}
        validationSchema={userFormSchema}
        onSubmit={onSubmit}
      &gt;
        {({ isValid, dirty, isSubmitting }) =&gt; (
          &lt;Form&gt;
            &lt;div className="form-control"&gt;
              &lt;label htmlFor="firstName"&gt;First Name&lt;/label&gt;
              &lt;Field type="text" id="firstName" name="firstName" /&gt;
              &lt;ErrorMessage name="firstName" component="div" className="error" /&gt;
            &lt;/div&gt;

            &lt;div className="form-control"&gt;
              &lt;label htmlFor="surname"&gt;Surname&lt;/label&gt;
              &lt;Field type="text" id="surname" name="surname" /&gt;
              &lt;ErrorMessage name="surname" component="div" className="error" /&gt;
            &lt;/div&gt;

            &lt;div className="form-control"&gt;
              &lt;label htmlFor="email"&gt;Email&lt;/label&gt;
              &lt;Field type="email" id="email" name="email" /&gt;
              &lt;ErrorMessage name="email" component="div" className="error" /&gt;
            &lt;/div&gt;

            &lt;div className="form-control"&gt;
              &lt;label htmlFor="dob"&gt;Date of Birth&lt;/label&gt;
              &lt;Field type="date" id="dob" name="dob" /&gt;
              &lt;ErrorMessage name="dob" component="div" className="error" /&gt;
            &lt;/div&gt;

            &lt;button type="submit" disabled={isSubmitting || !isValid}&gt;Submit&lt;/button&gt;
          &lt;/Form&gt;
        )}
      &lt;/Formik&gt;
</code></pre>
<p>In this code, we've utilsed the <code>&lt;Formik/&gt;</code> library component, which wraps around our standard <code>&lt;Form/&gt;</code>  element. We pass the following properties to the component:</p>
<ul>
<li><code>**initialValues**</code> – these are the required initial values of your form (that is when the form renders what values your inputs will have).‌ </li>
<li><strong><code>validationSchema</code> –</strong> this is probably the most important for this tutorial. Bear in mind this is an optional property, as it's not needed to utilise the <code>&lt;Formik/&gt;</code> component, but for any validation it is. ‌<br>‌‌<br>‌We're going to import our <code>userFormSchema</code> we created in the previous step. This is going to tell the form, when validating inputs within this form utilise these schemas. ‌</li>
<li><strong><code>onSubmit</code></strong> – a straightforward function to run on clicking your button / submitting the form. The values of the form will automatically be passed to this function.‌</li>
</ul>
<p>You can wrap the form within a "render prop" function also to utilise some of the exposed props from Formik within your form. You can learn about render props more <a target="_blank" href="https://legacy.reactjs.org/docs/render-props.html">here</a>.</p>
<pre><code class="lang-tsx">{({ isValid, isSubmitting }) =&gt; (
</code></pre>
<p><strong>Note:</strong> This is not required if you don't want to utilise any of the underlying Formik properties within the form itself. You can simply remove and place your opening <code>&lt;Form&gt;</code> tag in its place. ‌<br>‌‌<br>‌But using this render prop allows you to access properties exposed from the Formik component within your <code>&lt;Form/&gt;</code> element. You can see that we are utilising the<code>isValid</code> and <code>isSubmitting</code> properties to control the state of our submit button.</p>
<p>Continuing on with analyzing the code:</p>
<ul>
<li><code>**isValid**</code> – a boolean value which Formik controls based on our schema validation result.</li>
<li><code>**isSubmitting**</code> – A boolean flag indicating if a form is mid-submission. This flag is very useful when wanting to disable a button, to prevent multiple clicks meaning multiple submissions of the form.</li>
</ul>
<p>We can use these values to control the enablement of the submit button like so:</p>
<pre><code class="lang-tsx">&lt;button type="submit" disabled={isSubmitting || !isValid}&gt;Submit&lt;/button&gt;
</code></pre>
<h3 id="heading-input-fields">Input Fields</h3>
<p>It's important to note that when using Formik and Yup, in order for the validation to work, the names of the input fields need to match the Yup schema keys exactly (case sensitive) – otherwise the validation rules won't be registered.</p>
<p><strong>Example:‌</strong></p>
<pre><code class="lang-tsx">&lt;Field type="email" id="email" name="email" /&gt;
&lt;ErrorMessage name="email" component="div" className="error" /&gt;
</code></pre>
<p>We've defined this field is to be used for an email input, and given it the matching <code>name</code> of "email" to our a userFormSchema definition.</p>
<p>Underneath, we code our Formik <code>&lt;ErrorMessage/&gt;</code> component, again passing in the name of '<em>email'</em>, matching our schema. Using the name property we are able to link our input, error message, and validation schemas all together. </p>
<p>If there are any issues with validating the input field, the error message will show any defined error messages – otherwise it will fallback to a default message, e.g "<em>firstname is a required field</em>". This can be less user friendly, so I'd recommend always passing a custom message.</p>
<p>You'll also notice, that when we lose focus or when typing (after first validation has run), it will automatically run validation again. You can overwrite this functionality by setting the <code>validateOnBlur</code> and the <code>validateOnChange</code> flags (true / false).</p>
<p>As an example, it will look like this in its error state.:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/image-100.png" alt="Image: Invalid Formik form showing error state" width="600" height="400" loading="lazy">
<em>Image: Invalid Formik form showing error state</em></p>
<p>‌Once we've entered values for all inputs, and our validation has passed (you can see the submit button is now enabled), we can submit.‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/image-95.png" alt="Image: Valid Formik form showing valid state" width="600" height="400" loading="lazy">
<em></em></p><div id="ember289" class="miw-100 tc bn form-text bg-transparent pr8 pl8 ember-view" data-kg-has-link-toolbar="true" data-koenig-dnd-disabled="true"><div class="koenig-basic-html-input__editor-wrappper"><div class="koenig-basic-html-input__editor __mobiledoc-editor" data-gramm="false" data-kg="editor" data-kg-allow-clickthrough="" data-placeholder="Type caption for image (optional)"><p><em>Image: Valid User form with enabled submit button</em></p></div></div></div><p></p>
<h3 id="heading-further-validation-and-formik-features">Further Validation and Formik Features‌</h3>
<p>You've now seen how easy Yup and Formik can make creating a form. It has full validation and even error handling, meaning you can have a fully functioning user friendly form built in just a few minutes.</p>
<p>But what if you want to add more complex validation to a much larger / complicated form? Well, let's look at an example:</p>
<p>Let's say we want to validate that the date of birth provided ensures that the user is over the age of 18. We will also add a password field, which will have rules of:</p>
<ul>
<li>minimum of 6 letters</li>
<li>contain a number</li>
<li>contain a special character</li>
</ul>
<h4 id="heading-dob-extra-requirements">DoB Extra Requirements</h4>
<p>We can do this by chaining the <code>test()</code> function onto the <code>string()</code> function of the dob object within our schema.</p>
<p>The <code>test()</code> function allows us to test against custom logic. Update the <code>dob</code> parameter within the userFormSchema to the following:‌</p>
<pre><code class="lang-ts">dob: Yup.string()
      .required(<span class="hljs-string">'Date of Birth is required'</span>)
      .test(<span class="hljs-string">'is-older-than-18'</span>, <span class="hljs-string">'You must be at least 18 years old'</span>, <span class="hljs-function">(<span class="hljs-params">value</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (!value) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

        <span class="hljs-comment">// try to parse the value to date</span>
        <span class="hljs-keyword">const</span> parsedDate = parse(value, <span class="hljs-string">'yyyy-MM-dd'</span>, <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>());
        <span class="hljs-keyword">if</span> (!isValid(parsedDate)) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

        <span class="hljs-keyword">const</span> today = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>();
        <span class="hljs-keyword">const</span> eighteenYearsAgo = subYears(today, <span class="hljs-number">18</span>);

        <span class="hljs-comment">// check if date provided is before or the same as 18 years ago.</span>
        <span class="hljs-keyword">return</span> parsedDate &lt;= eighteenYearsAgo;
      })
</code></pre>
<p>We now get the following error when trying to submit a date that is less than 18 years ago. ‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/image-99.png" alt="Image showing Invalid date input field due to failed date validation" width="600" height="400" loading="lazy">
<em>Image: Invalid input field due to failed date validation</em></p>
<h4 id="heading-password-validation">Password Validation</h4>
<p>For the password field validation, we can do something like this:‌</p>
<pre><code class="lang-ts">password: Yup.string()
    .required(<span class="hljs-string">'This field is required'</span>)
    .min(<span class="hljs-number">6</span>, <span class="hljs-string">'Must be at least 6 characters'</span>)
    .matches(<span class="hljs-regexp">/[!@#$%^&amp;*(),.?":{}|&lt;&gt;]/</span>, <span class="hljs-string">'Must contain at least one special character'</span>)
    .matches(<span class="hljs-regexp">/\d/</span>, <span class="hljs-string">'Must contain at least one number'</span>);
</code></pre>
<p>Here we use the <code>matches()</code> function, passing in a regular expression to assert against. You could combine these cases into one regular expression, but the benefit of keeping them separate is it allows you to pinpoint which validation rule is failing. It also allows for a more granular error message and maintenance should the rules change in the future.</p>
<h3 id="heading-other-useful-methods">Other Useful Methods:</h3>
<ul>
<li><code>length()</code> – asserts the length of the string / number</li>
<li><code>positive()</code> – asserts the number type is a positive number</li>
<li><code>email()</code> – asserts that it is a valid email address</li>
<li><code>url()</code>  – asserts that it is a valid URL </li>
<li><code>min()</code> / <code>max()</code> – asserts that the number is at least 'x' and less than 'y'</li>
<li><code>ensure()</code> – transforms <code>undefined</code> and <code>null</code> values to an empty string along with setting the <code>default</code> to an empty string.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>As you can see, the possibilities with Yup are vast. Then combine this with the Formik library, and you can have rich, efficient, and easy to use forms. </p>
<p>This ease of use makes it so much quicker to get a form up and running on your web or mobile application, allowing you to focus on user experience, design, and business logic. </p>
<p>As always feel free to reach and discuss this article with me on <a target="_blank" href="https://x.com/grantdotdev">Twitter</a>, and don't forget to drop me a follow to hear about future articles and dev tips.   </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What are Controlled and Uncontrolled Components in React.js? ]]>
                </title>
                <description>
                    <![CDATA[ In React.js, managing form inputs and user interactions is a crucial part of building dynamic web applications.  Two key concepts that developers need to understand are controlled and uncontrolled components. These concepts define how form data is ha... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-are-controlled-and-uncontrolled-components-in-react/</link>
                <guid isPermaLink="false">66c4c41fbd556981b1bdc443</guid>
                
                    <category>
                        <![CDATA[ components ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joan Ayebola ]]>
                </dc:creator>
                <pubDate>Fri, 21 Jun 2024 20:18:52 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/Ivory-and-Blue-Lavender-Aesthetic-Photo-Collage-Presentation--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In React.js, managing form inputs and user interactions is a crucial part of building dynamic web applications. </p>
<p>Two key concepts that developers need to understand are controlled and uncontrolled components. These concepts define how form data is handled within a React component. </p>
<p>Controlled components rely on React state to manage the form data, while uncontrolled components use the DOM itself to handle form data. </p>
<p>In this article, we will explore the differences between controlled and uncontrolled components, how to implement them, and some best practices for using each approach in your React applications.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-are-controlled-components">What are Controlled Components</a>?</li>
<li><a class="post-section-overview" href="#heading-how-controlled-components-work">How Controlled Components Work</a> </li>
<li><a class="post-section-overview" href="#heading-benefits-of-using-controlled-components">Benefits of using Controlled Components</a></li>
<li><a class="post-section-overview" href="#heading-examples-of-controlled-components">Examples of Controlled Components</a></li>
<li><a class="post-section-overview" href="#heading-what-are-uncontrolled-components">What are Uncontrolled Components</a>?</li>
<li><a class="post-section-overview" href="#heading-how-uncontrolled-components-work">How Uncontrolled Components Work</a></li>
<li><a class="post-section-overview" href="#heading-when-to-use-uncontrolled-components">When to use Uncontrolled Components</a></li>
<li><a class="post-section-overview" href="#heading-limitations-of-uncontrolled-components">Limitations to Uncontrolled Components</a></li>
<li><a class="post-section-overview" href="#heading-examples-of-uncontrolled-components">Examples of Uncontrolled Components</a></li>
<li><a class="post-section-overview" href="#heading-factors-to-consider-when-choosing-between-controlled-and-uncontrolled-components">Factors to Consider When Choosing Between Controlled and Uncontrolled Components</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-what-are-controlled-components">What are Controlled Components?</h2>
<p>Controlled components are form elements (like <code>input</code>, <code>textarea</code>, or <code>select</code>) that are managed by React state. This means that the value of the form element is set and updated through React state, making React the "single source of truth" for the form data. </p>
<p>By controlling form elements via state, you gain more control over user interactions and can easily enforce validation, format data, and respond to changes.</p>
<p>Here's an example of a controlled component:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { 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">ControlledComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [value, setValue] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setValue(event.target.value);
  };

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
    alert(<span class="hljs-string">'A name was submitted: '</span> + value);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
        Name:
        <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">value</span>=<span class="hljs-string">{value}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</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">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Submit<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>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ControlledComponent;
</code></pre>
<p>In this example:</p>
<ul>
<li>The <code>value</code> state holds the current value of the input field.</li>
<li>The <code>handleChange</code> function updates the state whenever the user types in the input field.</li>
<li>The <code>handleSubmit</code> function handles the form submission, using the current state value.</li>
</ul>
<h2 id="heading-how-controlled-components-work">How Controlled Components Work</h2>
<p>Controlled components in React ensure that the form data is handled by the React state, providing a consistent and predictable way to manage user input. </p>
<p>Here’s a breakdown of how these components work, including state management in the parent component, passing values as props to child components, handling user input with event handlers, and updating state in the parent component.</p>
<h3 id="heading-state-management-in-the-parent-component">State Management in the Parent Component</h3>
<p>State management is often handled in the parent component, especially when multiple child components need to interact or share state. The parent component maintains the state and passes it down to child components via props.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ChildComponent <span class="hljs-keyword">from</span> <span class="hljs-string">'./ChildComponent'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ParentComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [inputValue, setInputValue] = useState(<span class="hljs-string">''</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>Controlled Component Example<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{inputValue}</span> <span class="hljs-attr">setValue</span>=<span class="hljs-string">{setInputValue}</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> ParentComponent;
</code></pre>
<h3 id="heading-passing-values-as-props-to-a-child-component">Passing Values as Props to a Child Component</h3>
<p>The parent component passes the state value and a state updater function to the child component as props. This allows the child component to display the current state and update it when needed.</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-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ChildComponent</span>(<span class="hljs-params">{ value, setValue }</span>) </span>{
  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setValue(event.target.value);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
        Name:
        <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">value</span>=<span class="hljs-string">{value}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</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">form</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ChildComponent;
</code></pre>
<h3 id="heading-handling-user-input-with-event-handlers">Handling User Input with Event Handlers</h3>
<p>Event handlers are used to manage user input. When the user types into the input field, the <code>onChange</code> event triggers the <code>handleChange</code> function, which updates the state in the parent component.</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ChildComponent</span>(<span class="hljs-params">{ value, setValue }</span>) </span>{
  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setValue(event.target.value);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
        Name:
        <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">value</span>=<span class="hljs-string">{value}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</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">form</span>&gt;</span></span>
  );
}
</code></pre>
<h3 id="heading-updating-state-in-a-parent-component">Updating State in a Parent Component</h3>
<p>When the state updater function (<code>setValue</code>) is called in the child component, it updates the state in the parent component. This causes the parent component to re-render, which in turn re-renders the child component with the new state value.</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ParentComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [inputValue, setInputValue] = useState(<span class="hljs-string">''</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>Controlled Component Example<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{inputValue}</span> <span class="hljs-attr">setValue</span>=<span class="hljs-string">{setInputValue}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<h3 id="heading-putting-it-all-together">Putting It All Together</h3>
<p>Here's the complete example showing how controlled components work with state management in the parent component:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// ParentComponent.jsx</span>
<span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ChildComponent <span class="hljs-keyword">from</span> <span class="hljs-string">'./ChildComponent'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ParentComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [inputValue, setInputValue] = useState(<span class="hljs-string">''</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>Controlled Component Example<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ChildComponent</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{inputValue}</span> <span class="hljs-attr">setValue</span>=<span class="hljs-string">{setInputValue}</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> ParentComponent;

<span class="hljs-comment">// ChildComponent.jsx</span>
<span class="hljs-keyword">import</span> React <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">ChildComponent</span>(<span class="hljs-params">{ value, setValue }</span>) </span>{
  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setValue(event.target.value);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span>&gt;</span>
        Name:
        <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">value</span>=<span class="hljs-string">{value}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</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">form</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ChildComponent;
</code></pre>
<p>Controlled components in React provide a good way to manage form data by using React state as the single source of truth. This approach involves managing state in the parent component, passing values and state updater functions as props to child components, handling user input with event handlers, and updating state in the parent component. </p>
<p>This method ensures consistent and predictable form behavior, making it easier to implement validation, conditional rendering, and other interactive features.</p>
<h2 id="heading-benefits-of-using-controlled-components">Benefits of Using Controlled Components</h2>
<p>Controlled components offer several advantages that can significantly improve the development experience and functionality of React applications. Here are the key benefits:</p>
<h3 id="heading-predictable-state-management">Predictable State Management</h3>
<p>Using controlled components ensures that the form data is always in sync with the React state. This predictability comes from having a single source of truth for the data, which is the state itself. </p>
<p>Since the state drives the UI, any change in the state immediately reflects in the form elements and vice versa. This makes it easier to debug and understand how data flows through your application.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { 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">PredictableForm</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [name, setName] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setName(event.target.value);
  };

  <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">"text"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{name}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Current value: {name}<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>
<p>In this example, the input field and the displayed text are always synchronized, providing a predictable behavior.</p>
<h3 id="heading-easier-form-validation">Easier Form Validation</h3>
<p>Controlled components make it straightforward to implement form validation. Since the form data is stored in the component state, you can easily validate it before updating the state or on form submission. This approach allows you to provide real-time feedback to users as they interact with the form.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { 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">ValidatedForm</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> [error, setError] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> value = event.target.value;
    setEmail(value);

    <span class="hljs-keyword">if</span> (!value.includes(<span class="hljs-string">'@'</span>)) {
      setError(<span class="hljs-string">'Invalid email address'</span>);
    } <span class="hljs-keyword">else</span> {
      setError(<span class="hljs-string">''</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">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span> /&gt;</span>
      {error &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">p</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>{error}<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>
<p>Here, the validation logic runs on every change, providing immediate feedback to the user if the input is invalid.</p>
<h3 id="heading-integration-with-complex-ui-libraries">Integration with Complex UI Libraries</h3>
<p>Controlled components integrate seamlessly with complex UI libraries and frameworks, such as Redux for state management or Formik for handling forms. </p>
<p>By managing form data in the component state, you can easily connect your forms to these libraries and benefit from their advanced features like global state management, asynchronous data fetching, and more.</p>
<p><strong>Example with Formik:</strong></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> { Formik, Form, Field, ErrorMessage } <span class="hljs-keyword">from</span> <span class="hljs-string">'formik'</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Yup <span class="hljs-keyword">from</span> <span class="hljs-string">'yup'</span>;

<span class="hljs-keyword">const</span> SignupForm = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Formik</span>
    <span class="hljs-attr">initialValues</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">email:</span> '' }}
    <span class="hljs-attr">validationSchema</span>=<span class="hljs-string">{Yup.object({</span>
      <span class="hljs-attr">email:</span> <span class="hljs-attr">Yup.string</span>()<span class="hljs-attr">.email</span>('<span class="hljs-attr">Invalid</span> <span class="hljs-attr">email</span> <span class="hljs-attr">address</span>')<span class="hljs-attr">.required</span>('<span class="hljs-attr">Required</span>'),
    })}
    <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{(values,</span> { <span class="hljs-attr">setSubmitting</span> }) =&gt;</span> {
      setTimeout(() =&gt; {
        alert(JSON.stringify(values, null, 2));
        setSubmitting(false);
      }, 400);
    }}
  &gt;
    {({ isSubmitting }) =&gt; (
      <span class="hljs-tag">&lt;<span class="hljs-name">Form</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Field</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">ErrorMessage</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">component</span>=<span class="hljs-string">"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>&gt;</span>
          Submit
        <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 class="hljs-tag">&lt;/<span class="hljs-name">Formik</span>&gt;</span></span>
);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> SignupForm;
</code></pre>
<p>In this example, Formik handles form state and validation, demonstrating how controlled components can be part of more complex setups.</p>
<p>Controlled components provide predictable state management, easier form validation, and seamless integration with complex UI libraries. </p>
<p>By keeping the form data in the React state, you ensure consistency and control over your application's behavior, making it easier to build and maintain interactive and dynamic user interfaces.</p>
<h2 id="heading-examples-of-controlled-components">Examples of Controlled Components</h2>
<p>Controlled components are fundamental in React for handling form inputs in a predictable and manageable way. </p>
<p>Here are some examples of how you can implement controlled components for various types of form inputs, including text fields, email fields, password fields, select menus, checkboxes, and radio buttons.</p>
<h3 id="heading-input-fields-text-email-password">Input Fields (Text, Email, Password)</h3>
<h5 id="heading-text-input">Text Input</h5>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { 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">TextInput</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [text, setText] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setText(event.target.value);
  };

  <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">label</span>&gt;</span>
        Text:
        <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">value</span>=<span class="hljs-string">{text}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</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">p</span>&gt;</span>Entered Text: {text}<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> TextInput;
</code></pre>
<h5 id="heading-email-input">Email Input</h5>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { 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">EmailInput</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> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setEmail(event.target.value);
  };

  <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">label</span>&gt;</span>
        Email:
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{email}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</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">p</span>&gt;</span>Entered Email: {email}<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> EmailInput;
</code></pre>
<h5 id="heading-password-input">Password Input</h5>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { 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">PasswordInput</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [password, setPassword] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setPassword(event.target.value);
  };

  <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">label</span>&gt;</span>
        Password:
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{password}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</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">p</span>&gt;</span>Entered Password: {password}<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> PasswordInput;
</code></pre>
<h4 id="heading-select-menus">Select Menus</h4>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { 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">SelectMenu</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [option, setOption] = useState(<span class="hljs-string">'option1'</span>);

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setOption(event.target.value);
  };

  <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">label</span>&gt;</span>
        Choose an option:
        <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{option}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"option1"</span>&gt;</span>Option 1<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">"option2"</span>&gt;</span>Option 2<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">"option3"</span>&gt;</span>Option 3<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">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Selected Option: {option}<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> SelectMenu;
</code></pre>
<h4 id="heading-checkboxes">Checkboxes</h4>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { 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">Checkbox</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [isChecked, setIsChecked] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setIsChecked(event.target.checked);
  };

  <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">label</span>&gt;</span>
        Accept Terms:
        <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">{isChecked}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</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">p</span>&gt;</span>Checked: {isChecked ? 'Yes' : 'No'}<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> Checkbox;
</code></pre>
<h4 id="heading-radio-buttons">Radio Buttons</h4>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { 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">RadioButton</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [selectedOption, setSelectedOption] = useState(<span class="hljs-string">'option1'</span>);

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    setSelectedOption(event.target.value);
  };

  <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">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">"radio"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">"option1"</span>
          <span class="hljs-attr">checked</span>=<span class="hljs-string">{selectedOption</span> === <span class="hljs-string">'option1'</span>}
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
        /&gt;</span>
        Option 1
      <span class="hljs-tag">&lt;/<span class="hljs-name">label</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">"radio"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">"option2"</span>
          <span class="hljs-attr">checked</span>=<span class="hljs-string">{selectedOption</span> === <span class="hljs-string">'option2'</span>}
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
        /&gt;</span>
        Option 2
      <span class="hljs-tag">&lt;/<span class="hljs-name">label</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">"radio"</span>
          <span class="hljs-attr">value</span>=<span class="hljs-string">"option3"</span>
          <span class="hljs-attr">checked</span>=<span class="hljs-string">{selectedOption</span> === <span class="hljs-string">'option3'</span>}
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
        /&gt;</span>
        Option 3
      <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Selected Option: {selectedOption}<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> RadioButton;
</code></pre>
<p>Controlled components provide a clear and consistent way to handle form inputs in React. By using React state to manage the values of input fields, select menus, checkboxes, and radio buttons, you ensure that the UI remains in sync with the state. </p>
<p>This approach simplifies validation, makes data handling predictable, and facilitates integration with complex UI libraries.</p>
<h2 id="heading-what-are-uncontrolled-components">What are Uncontrolled Components?</h2>
<p>Uncontrolled components in React manage their own state internally rather than relying on React state. This approach is useful for simple forms where you don't need to manipulate the input data through React state updates.</p>
<p><strong>Example:</strong></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { Component } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UncontrolledComponent</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span> </span>{
  <span class="hljs-keyword">constructor</span>(props) {
    <span class="hljs-built_in">super</span>(props);
    <span class="hljs-comment">// Create a ref to hold the input DOM element</span>
    <span class="hljs-built_in">this</span>.inputRef = React.createRef();
  }

  handleSubmit = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Access the input value using the ref</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.inputRef.current.value);
  }

  render() {
    <span class="hljs-keyword">return</span> (
      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        {/* Use ref attribute to attach the ref to the input element */}
        <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">ref</span>=<span class="hljs-string">{this.inputRef}</span> 
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{this.handleSubmit}</span>&gt;</span>Submit<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>
<ul>
<li><strong>Ref Usage:</strong> In uncontrolled components, we use the <code>ref</code> attribute to create a reference (<code>this.inputRef</code>) to the DOM node of the input field.</li>
<li><strong>Handling Input:</strong> When the user enters data and clicks "Submit", <code>this.inputRef.current.value</code> allows us to directly access the current value of the input field without involving React state.</li>
<li><strong>Advantages:</strong> Uncontrolled components can be simpler and faster for basic form handling. They are often used when the form data is not needed in React state for any processing or validation.</li>
</ul>
<p><strong>Key Points:</strong></p>
<ul>
<li><strong>Internal State:</strong> Uncontrolled components manage their state internally with the help of refs, not with React state updates.</li>
<li><strong>Direct DOM Access:</strong> Accessing form data is done directly through DOM refs (<code>this.inputRef.current.value</code>).</li>
<li><strong>Simplicity:</strong> They are straightforward for simple forms where real-time validation or complex form interactions are not necessary.</li>
</ul>
<p>Uncontrolled components are handy in scenarios where you want a lightweight approach to handling form data without the overhead of managing state in React.</p>
<h2 id="heading-how-uncontrolled-components-work">How Uncontrolled Components Work</h2>
<p>Uncontrolled components manage their state internally using DOM refs (<code>useRef</code> hook in functional components or <code>React.createRef()</code> in class components) to access form element values directly. </p>
<p>Unlike controlled components, where form data is managed through React state and updated via <code>setState</code>, uncontrolled components bypass React's state management for handling form inputs.</p>
<h3 id="heading-direct-dom-access-with-useref-hook">Direct DOM Access with useRef Hook</h3>
<p>In functional components, the <code>useRef</code> hook allows us to create a mutable reference that persists across renders. We can use this ref to directly access DOM nodes, such as input fields.</p>
<p><strong>Example:</strong></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-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UncontrolledComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> inputRef = useRef(<span class="hljs-literal">null</span>); <span class="hljs-comment">// Create a ref to hold the input DOM element</span>

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Access the input value using the ref</span>
    <span class="hljs-built_in">console</span>.log(inputRef.current.value);
  };

  <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">"text"</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{inputRef}</span> /&gt;</span>
      <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 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> UncontrolledComponent;
</code></pre>
<h3 id="heading-accessing-an-elements-value-on-submit">Accessing an Element's Value on Submit</h3>
<p>In the example above:</p>
<ul>
<li><strong>Creating a Ref:</strong> <code>const inputRef = useRef(null);</code> initializes a ref named <code>inputRef</code> to hold the reference to the input DOM element.</li>
<li><strong>Handling Submit:</strong> When the "Submit" button is clicked (<code>onClick={handleSubmit}</code>), the <code>handleSubmit</code> function retrieves the current value of the input field using <code>inputRef.current.value</code>.</li>
</ul>
<p><strong>Key Points:</strong></p>
<ul>
<li><strong>DOM Access:</strong> The <code>useRef</code> hook allows direct access to DOM elements, enabling us to interact with them without updating React state.</li>
<li><strong>Form Submission:</strong> On form submission (<code>onClick={handleSubmit}</code>), the function accesses the current value of the input field through <code>inputRef.current.value</code>.</li>
<li><strong>Simplicity:</strong> Uncontrolled components are straightforward for basic form handling scenarios where direct DOM manipulation suffices, avoiding the need for managing state updates in React.</li>
</ul>
<p>Using uncontrolled components with <code>useRef</code> is particularly useful for handling forms where real-time validation or complex interactions aren't necessary, focusing instead on simplicity and performance.</p>
<h2 id="heading-when-to-use-uncontrolled-components">When to Use Uncontrolled Components</h2>
<p>Uncontrolled components are ideal in specific scenarios where simplicity and direct DOM manipulation are advantageous over managing state with React. </p>
<p>Here are the key situations when using uncontrolled components is beneficial:</p>
<h3 id="heading-1-simple-forms-with-limited-interactions">1. Simple Forms with Limited Interactions</h3>
<p>Uncontrolled components shine in scenarios where:</p>
<ul>
<li><strong>The Forms Arent' That Complex:</strong> The form is straightforward with minimal input fields and does not require complex validation or dynamic updates based on other form inputs.</li>
<li><strong>Performance is Important:</strong> Directly accessing form values via DOM refs (<code>useRef</code> or <code>React.createRef()</code>) can be more performant than updating React state for each input change, especially in large forms.</li>
<li><strong>You want Simplicity:</strong> When you prefer a simpler implementation without managing state updates and re-renders for form inputs.</li>
</ul>
<h3 id="heading-2-focus-management-selecting-text">2. Focus Management (Selecting Text)</h3>
<p>In some cases, you might need to manage user interaction such as selecting text within an input field or programmatically focusing on a specific input without triggering React state updates unnecessarily. </p>
<p>Uncontrolled components allow you to:</p>
<ul>
<li><strong>Directly manipulate the DOM:</strong> Use DOM methods like <code>select()</code> on the input element directly via refs to manage focus or text selection.</li>
<li><strong>Handling focus and text selection directly with refs</strong>: This can be more efficient and straightforward compared to triggering state updates and managing focus state in React components.</li>
</ul>
<h4 id="heading-example-use-case">Example Use Case:</h4>
<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-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UncontrolledComponent</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> inputRef = useRef(<span class="hljs-literal">null</span>); <span class="hljs-comment">// Create a ref to hold the input DOM element</span>

  <span class="hljs-keyword">const</span> handleFocus = <span class="hljs-function">() =&gt;</span> {
    inputRef.current.select(); <span class="hljs-comment">// Selects all text in the input field</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">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{inputRef}</span> <span class="hljs-attr">defaultValue</span>=<span class="hljs-string">"Initial Value"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleFocus}</span>&gt;</span>Select Text<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> UncontrolledComponent;
</code></pre>
<p>In this example, clicking the "Select Text" button calls <code>inputRef.current.select()</code> to select all text within the input field directly, without involving React state updates. This is a simple yet effective use of uncontrolled components for managing focus and text selection.</p>
<h2 id="heading-limitations-of-uncontrolled-components">Limitations of Uncontrolled Components</h2>
<p>Using uncontrolled components in React can offer simplicity and performance benefits in certain scenarios, but they also come with limitations that are important to consider:</p>
<h3 id="heading-difficulty-in-form-validation">Difficulty in Form Validation:</h3>
<ul>
<li>Uncontrolled components can make form validation more challenging compared to controlled components. Since the form data is managed internally by the DOM rather than React state, validating and ensuring data consistency across multiple inputs can be complex.</li>
<li>Validation logic often involves accessing and checking each input's value directly through refs (<code>ref.current.value</code>). This approach can lead to more manual and error-prone validation code, especially in forms with complex validation requirements.</li>
</ul>
<h3 id="heading-less-predictable-state-management">Less Predictable State Management:</h3>
<ul>
<li>Uncontrolled components bypass React's state management, which can lead to less predictable state handling in complex applications. Changes in form data are not automatically synchronized with React's state updates or other component state, potentially leading to inconsistencies.</li>
<li>This lack of synchronization can make it challenging to maintain a single source of truth for form data across different components or when integrating with other state management solutions like Redux or Context API.</li>
</ul>
<h3 id="heading-limited-react-ecosystem-integration">Limited React Ecosystem Integration:</h3>
<ul>
<li>Uncontrolled components may not fully leverage React's ecosystem features, such as state persistence, time-travel debugging (with Redux), or seamless integration with third-party libraries designed for controlled components.</li>
<li>Components relying on React state benefit from these features, enhancing developer productivity and application maintainability.</li>
</ul>
<h2 id="heading-examples-of-uncontrolled-components">Examples of Uncontrolled Components</h2>
<p>Uncontrolled components in React are particularly useful for handling input fields and textarea elements where direct DOM manipulation suffices, and React state management isn't necessary. </p>
<p>Here are examples of how uncontrolled components can be applied:</p>
<h3 id="heading-1-input-fields-read-only-or-pre-filled-data">1. Input Fields (Read-only or Pre-filled Data)</h3>
<p>Uncontrolled components can be used when you need to display read-only or pre-filled data in an input field without managing its state in React.</p>
<p><strong>Example:</strong></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-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UncontrolledInput</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> initialValue = <span class="hljs-string">'Hello, World!'</span>;
  <span class="hljs-keyword">const</span> inputRef = useRef(<span class="hljs-literal">null</span>); <span class="hljs-comment">// Create a ref to hold the input DOM element</span>

  <span class="hljs-keyword">const</span> handleFocus = <span class="hljs-function">() =&gt;</span> {
    inputRef.current.select(); <span class="hljs-comment">// Selects all text in the input field on focus</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {/* Using defaultValue for pre-filled data */}
      <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">ref</span>=<span class="hljs-string">{inputRef}</span> <span class="hljs-attr">defaultValue</span>=<span class="hljs-string">{initialValue}</span> <span class="hljs-attr">readOnly</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleFocus}</span>&gt;</span>Select Text<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> UncontrolledInput;
</code></pre>
<p>In this example:</p>
<ul>
<li>The <code>defaultValue</code> attribute sets the initial value of the input field.</li>
<li><code>readOnly</code> attribute prevents users from editing the input field, making it read-only.</li>
<li><code>useRef</code> hook manages focus and selection of text within the input field using <code>inputRef.current</code>.</li>
</ul>
<h3 id="heading-2-textarea-elements">2. Textarea Elements</h3>
<p>Uncontrolled components are also applicable to textarea elements, especially when dealing with multiline text input where immediate state updates are not necessary.</p>
<p><strong>Example:</strong></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-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UncontrolledTextarea</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> initialText = <span class="hljs-string">'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'</span>;
  <span class="hljs-keyword">const</span> textareaRef = useRef(<span class="hljs-literal">null</span>); <span class="hljs-comment">// Create a ref to hold the textarea DOM element</span>

  <span class="hljs-keyword">const</span> handleClear = <span class="hljs-function">() =&gt;</span> {
    textareaRef.current.value = <span class="hljs-string">''</span>; <span class="hljs-comment">// Clear textarea content directly</span>
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      {/* Using defaultValue for pre-filled content */}
      <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{textareaRef}</span> <span class="hljs-attr">defaultValue</span>=<span class="hljs-string">{initialText}</span> <span class="hljs-attr">rows</span>=<span class="hljs-string">{4}</span> <span class="hljs-attr">cols</span>=<span class="hljs-string">{50}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleClear}</span>&gt;</span>Clear Text<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> UncontrolledTextarea;
</code></pre>
<p>In this example:</p>
<ul>
<li>The <code>defaultValue</code> attribute sets the initial content of the textarea.</li>
<li><code>useRef</code> hook manages direct manipulation of textarea content using <code>textareaRef.current</code>.</li>
<li><code>rows</code> and <code>cols</code> attributes define the dimensions of the textarea.</li>
</ul>
<p><strong>Key points:</strong></p>
<ul>
<li><strong>Direct DOM Access:</strong> Uncontrolled components leverage <code>useRef</code> to directly manipulate DOM elements for managing input fields and textarea content.</li>
<li><strong>Performance:</strong> Suitable for scenarios where real-time updates or complex state management aren't required, enhancing performance by avoiding unnecessary state updates.</li>
<li><strong>Simplicity:</strong> Provides a straightforward approach to handling form elements with default or read-only values, maintaining simplicity in component logic.</li>
</ul>
<p>These examples demonstrate how uncontrolled components can handle input fields and textarea elements effectively in React applications, focusing on simplicity and direct DOM manipulation for specific use cases.</p>
<h2 id="heading-factors-to-consider-when-choosing-between-controlled-and-uncontrolled-components">Factors to Consider When Choosing Between Controlled and Uncontrolled Components</h2>
<p>When deciding between controlled and uncontrolled components in React, several factors should be considered to determine which approach best suits your application's requirements. Here are key considerations for each factor:</p>
<h3 id="heading-1-complexity-of-form">1. Complexity of Form</h3>
<h4 id="heading-controlled-components">Controlled Components:</h4>
<ul>
<li><strong>Advantages:</strong> Suitable for complex forms where you need precise control over the form state and its interaction with other components.</li>
<li><strong>Usage:</strong> Use controlled components when form inputs depend on each other, require validation, or when you need to synchronize form state across multiple components or pages.</li>
</ul>
<h4 id="heading-uncontrolled-components">Uncontrolled Components:</h4>
<ul>
<li><strong>Advantages:</strong> Simplify implementation for basic forms with minimal interactivity or where direct DOM manipulation suffices.</li>
<li><strong>Usage:</strong> Ideal for simple forms without complex validation or when managing form state in React isn't necessary for your use case.</li>
</ul>
<h3 id="heading-2-need-for-form-validation">2. Need for Form Validation</h3>
<h4 id="heading-controlled-components-1">Controlled Components:</h4>
<ul>
<li><strong>Advantages:</strong> Easier integration with form validation libraries (for example, Formik, Yup) since form state is managed within React state.</li>
<li><strong>Usage:</strong> Use controlled components when implementing complex validation rules, such as conditional validation or asynchronous validation logic.</li>
</ul>
<h4 id="heading-uncontrolled-components-1">Uncontrolled Components:</h4>
<ul>
<li><strong>Challenges:</strong> Handling form validation can be more manual and less integrated, as form data is managed directly through DOM manipulation.</li>
<li><strong>Usage:</strong> Consider uncontrolled components for simple forms where validation requirements are minimal or where custom validation logic can be managed without relying heavily on React state updates.</li>
</ul>
<h3 id="heading-3-integration-with-external-libraries">3. Integration with External Libraries</h3>
<h4 id="heading-controlled-components-2">Controlled Components:</h4>
<ul>
<li><strong>Advantages:</strong> Seamlessly integrates with external state management solutions like Redux or React's Context API for managing global application state.</li>
<li><strong>Usage:</strong> Prefer controlled components when your application requires integration with third-party libraries or when leveraging advanced React ecosystem features (for example, time-travel debugging with Redux).</li>
</ul>
<h4 id="heading-uncontrolled-components-2">Uncontrolled Components:</h4>
<ul>
<li><strong>Considerations:</strong> May require additional effort to integrate with external libraries that assume controlled component behavior.</li>
<li><strong>Usage:</strong> Use uncontrolled components when external state management isn't necessary, focusing on lightweight implementation and minimizing dependencies.</li>
</ul>
<h3 id="heading-additional-considerations">Additional Considerations:</h3>
<h4 id="heading-performance">Performance:</h4>
<p>Controlled components may incur overhead due to frequent state updates, whereas uncontrolled components can offer better performance for simple forms by reducing re-renders.</p>
<h4 id="heading-developer-preference">Developer Preference:</h4>
<p>Consider team familiarity and preferences with React state management patterns when deciding between controlled and uncontrolled components.</p>
<h3 id="heading-summary">Summary:</h3>
<p><strong>Choose Controlled Components</strong> for complex forms, robust validation needs, and seamless integration with external state management and validation libraries.</p>
<p><strong>Opt for Uncontrolled Components</strong> for simpler forms, minimal validation requirements, and when direct DOM manipulation provides sufficient functionality without the need for managing form state in React.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The choice between controlled and uncontrolled components in React hinges on several critical factors that determine the optimal approach for form management within your application.</p>
<p>Ultimately, the decision should align with your project's specific needs, considering factors such as form complexity, validation requirements, integration with external libraries, and developer preferences. </p>
<p>By carefully assessing these factors, you can implement the most effective form handling strategy in React that balances functionality, performance, and ease of maintenance.</p>
<p>Connect with me on <a target="_blank" href="https://linkedin.com/in/joanayebola">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Enhance Embedded Links in React with Microlinks ]]>
                </title>
                <description>
                    <![CDATA[ The web has evolved from rigid color coding and 2D rendering to an era of complex, aesthetically pleasing animations and 3D rendering options. There have also been integrations with new technologies, such as virtual reality tools and frameworks, to i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-enhance-embedded-links-in-react-with-microlinks/</link>
                <guid isPermaLink="false">66bb58ca7b4b3dfb6852274b</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwatobi ]]>
                </dc:creator>
                <pubDate>Tue, 18 Jun 2024 02:56:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/microl.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The web has evolved from rigid color coding and 2D rendering to an era of complex, aesthetically pleasing animations and 3D rendering options. There have also been integrations with new technologies, such as virtual reality tools and frameworks, to improve the user experience.</p>
<p>In this article, you'll learn how to optimize embedded links in your front-end development projects to meet your desired specifications. </p>
<p>The inspiration for this article came from a problem I encountered while creating a portfolio site and having issues embedding external sites—until I discovered an efficient tool to help.</p>
<p>To fully grasp this tutorial, there are some of the prerequisites:</p>
<ul>
<li>A good knowledge of JavaScript.</li>
<li>Familiarity with React JS and npm package installation.</li>
<li>Proficiency in CSS.</li>
</ul>
<p>Let's get started!</p>
<h2 id="heading-the-concept-of-micro-linking">The Concept of Micro-linking</h2>
<p>Micro-linking entails embedding a link to an external website within a default web page. Embedding links are different from the default HTML  <code>“alt href”</code>  attributes commonly used by web developers.</p>
<p>This concept also entails extracting relevant site metadata, information and relevant images from the embedded external site link. This contributes to providing more knowledge about the external website in question.</p>
<p>This feature isn’t all new as it's commonly used among high-end blog posts, video streaming sites and e-commerce sites. This feature is also utilized by site owners to customize how their site information is viewed when embedded in advertisement sites.</p>
<h2 id="heading-how-does-micro-linking-work">How Does Micro-linking Work?</h2>
<p>Ordinarily, embedding a URL using plain HTML code doesn’t generate any image or text preview. However, this isn’t the case for micro-links. This occurs due to the use of an application programming interface to extract relevant info from the site being referenced and then outputting it to the developer in JSON format for easy customization and usage. </p>
<p>There are quite a lot of micro-linking services available commercially. Some examples are <a target="_blank" href="https://embed.ly/">Embedly</a>, <a target="_blank" href="https://ogp.me/">Open Graph</a> protocol, <a target="_blank" href="https://microlink.io/">microlink.io</a>, and so on.</p>
<h2 id="heading-introduction-to-the-microlink-package">Introduction to the Microlink Package</h2>
<p>In this tutorial, we'll create a site that uses a Node package known as Microlink to generate previews. Details regarding URL customization will also be illustrated. </p>
<p>This is customization allows developers to easily extract relevant link previews from the Microlink site, skipping the hassle of interacting with the website interface. </p>
<p>For further learning, the library has a rich documentation site which can be accessed <a target="_blank" href="https://microlink.io/docs/sdk/integrations/react">here</a>.</p>
<h2 id="heading-how-to-set-up-your-project">How to Set Up Your Project</h2>
<p>To build the link preview site, we'll utilize the React Vite tool. Entering the command <code>npm create-vite-app@latest links</code> immediately spins up a folder named <code>latest links</code> which we'll use in building this project.</p>
<p>Also, the <code>microlink</code> package needs to be installed. To do that, navigate to the command line and run the <code>npm i @microlinks/react</code> command.</p>
<h2 id="heading-demo-project">Demo Project</h2>
<p>First of all, we'll be create the default JSX functional component for this project.</p>
<pre><code><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;&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>Next, we'll be import and initialize the installed <code>microlink</code> library:</p>
<pre><code><span class="hljs-keyword">import</span> Microlink <span class="hljs-keyword">from</span> <span class="hljs-string">'@microlink/react'</span>
</code></pre><p>After that, we can initialize the package within the App function:</p>
<pre><code><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">Microlink</span>
<span class="hljs-attr">url</span>= <span class="hljs-string">" https://tobilyn77.hashnode.dev/nodejs-clustering-and-load-balancing-comprehensive-overview "</span>  /&gt;</span>
<span class="hljs-tag">&lt;/&gt;</span></span>
)
</code></pre><p>The URL variable I included is a link to an external site I intend to preview on my local site. This can be changed to whichever site you would like to preview.</p>
<p>On running this, you should see something similar to this.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/micro1-1.JPG" alt="Image" width="600" height="400" loading="lazy">
<em>microlink project webpage</em></p>
<p>We have successfully set up a micro-link in our application. But that’s not all, the power of the package is enormous, providing a level of flexibility in controlling the layout and size of the micro-links.</p>
<h3 id="heading-size-tweaking">Size Tweaking</h3>
<p>Size tweaking simply involves adjusting the size or dimensions of a variable to suit different specifications. In this case, we'll adjust the size of the embedded links. </p>
<pre><code>&lt;Microlink
url= <span class="hljs-string">"https://tobilyn77.hashnode.dev/nodejs-clustering-and-load-balancing-comprehensive-overview"</span> /&gt;
<span class="xml"><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></span>
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Microlink</span>
<span class="hljs-attr">url</span>= <span class="hljs-string">"https://tobilyn77.hashnode.dev/nodejs-clustering-and-load-balancing-comprehensive-overview"</span>  <span class="hljs-attr">size</span>=<span class="hljs-string">"small"</span>/&gt;</span></span>
<span class="xml"><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></span>
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2024/06/micro2.JPG" alt="Image" width="600" height="400" loading="lazy">
<em>micro-links with different sizes</em></p>
<p>The code above specifies the size of the micro-link to be rendered. If the size is indicated to be <code>small</code>, the dimension of the micro-link gets altered. It also allows for large and medium sizes, and by default, the medium size is what is usually seen when no size dimension is specified.</p>
<p>Also, the <code>microlink</code> self-enclosing tag allows for CSS styling. This can be achieved by including the style variable within the <code>microlink</code> tag.</p>
<pre><code>&lt;Microlink
url= <span class="hljs-string">"https://tobilyn77.hashnode.dev/nodejs-clustering-and-load-balancing-comprehensive-overview"</span>
style= {{<span class="hljs-attr">color</span>: <span class="hljs-string">'red'</span>}} /&gt;
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2024/06/micro3.JPG" alt="Image" width="600" height="400" loading="lazy">
<em>micro-link with the color set to red</em></p>
<p>As you can see in the code above, the <code>microlink</code> was styled with the color red and that reflected in the output. Other CSS styling can also be applied to give users an aesthetic feel to your site.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>With this, we have come to the end of the tutorial. We hope you’ve learned link previewing via the <code>microlink</code> package.</p>
<p>Feel free to drop any questions or comments in the comment box below. You can also interact with me on my blog and check out my other articles  <a target="_blank" href="https://www.freecodecamp.org/news/p/cedba683-793c-4c78-85d9-c46647c75b71/linktr.ee/tobilyn77">here</a>. Till next time, keep on coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Multi-Page Animations Using Framer Motion & React-Router-Dom ]]>
                </title>
                <description>
                    <![CDATA[ Animations are what make plain websites turn into exciting and unforgettable experiences. They give your website a bit of personality and uniqueness and leave the visitor admiring the overall aesthetic. It's a no-brainer that humans love beautiful th... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-multi-page-animations-using-framer-motion-and-react-router-dom/</link>
                <guid isPermaLink="false">66d4608c230dff016690584f</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react router ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Okosa Leonard ]]>
                </dc:creator>
                <pubDate>Mon, 17 Jun 2024 05:57:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/Green-Abstract-Wavy-Background-Motivational-Quote-Facebook-Post.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Animations are what make plain websites turn into exciting and unforgettable experiences. They give your website a bit of personality and uniqueness and leave the visitor admiring the overall aesthetic.</p>
<p>It's a no-brainer that humans love beautiful things. We all love products that look easy on the eyes.</p>
<p>In this article, we're going to learn how to create animations that wow users with the use of Framer motion and React-Router-Dom.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To be able to follow what we're doing in this article, you should have some knowledge of <a target="_blank" href="https://react.dev/">React</a>, <a target="_blank" href="https://www.framer.com/motion/">Framer motion</a> and <a target="_blank" href="https://reactrouter.com/">React-Router-DOM</a>.</p>
<p>To learn Framer motion better, you can study their documentation.</p>
<p><a target="_blank" href="https://nodejs.org/en/download/package-manager">Node.js</a> should also be installed on your system, and you should have a working code editor. I'll be using <a target="_blank" href="https://code.visualstudio.com/">VS Code</a>.</p>
<h2 id="heading-how-to-set-up-the-project">How to Set Up the Project</h2>
<p>To set up our project we're going to use Vite to set up our React development environment.</p>
<ol>
<li><p>Open the terminal in VScode. You can use Ctrl + backtick(`)</p>
</li>
<li><p>In your terminal, enter the following command:</p>
</li>
</ol>
<pre><code class="lang-plaintext">npm create vite@latest
</code></pre>
<ol start="3">
<li><p>Follow the prompts to name your project and choose your desired framework. In our case, we're using React. This will be a JavaScript project.</p>
</li>
<li><p>Go to your project directory and use <code>npm i</code> in the terminal.</p>
</li>
<li><p>To start your project use <code>npm run dev</code>.</p>
</li>
<li><p>Remember to clean your project by removing the code in App.js and your CSS files in the <code>src</code> folder.</p>
</li>
</ol>
<h2 id="heading-how-to-initialize-framer-motion-and-react-router-dom">How to Initialize Framer Motion and React-Router-Dom</h2>
<ol>
<li>To install Framer-motion in your project open the terminal and enter:</li>
</ol>
<pre><code class="lang-plaintext">npm i framer-motion
</code></pre>
<ol start="2">
<li>To install React-Router-DOM in your project open the terminal and enter:</li>
</ol>
<pre><code class="lang-plaintext">npm i react-router-dom
</code></pre>
<h2 id="heading-how-to-set-up-components-and-basic-routing-with-react-router-dom">How to Set Up Components and Basic Routing with React-Router-DOM</h2>
<p>Let's set up our components and the pages we'll be routing to for this project.</p>
<ol>
<li><p>In <code>src</code>, create a new folder named <code>components</code>.</p>
</li>
<li><p>We'll add four files in this folder named <code>Home.jsx</code>, <code>About.jsx</code>, <code>Projects.jsx</code> and <code>Navbar.jsx</code>.</p>
</li>
<li><p>Inside the first three, we're going to create a React functional component. Change the content of the <code>h1</code> tag in each component:</p>
</li>
</ol>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> Home = <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>
     <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">h1</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> Home
</code></pre>
<ol start="4">
<li>In the Navbar, we need to import <code>Link</code> from React-Router-DOM to create anchor elements. We then need to create a container housing our logo and nav links. The logo will link the points to our index page.</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> {Link} <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router-dom"</span>

<span class="hljs-keyword">const</span> Navbar () =&gt; {
 <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">"nav"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"logo"</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-link"</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Lennythedev<span class="hljs-tag">&lt;/<span class="hljs-name">Link</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> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-links"</span>&gt;</span>
           <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-item"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-link"</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Home<span class="hljs-tag">&lt;/<span class="hljs-name">Link</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">"nav-item"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-link"</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">Link</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">"nav-item"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-link"</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>Projects<span class="hljs-tag">&lt;/<span class="hljs-name">Link</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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
 }
</code></pre>
<ol start="5">
<li>Now let's go to our <code>index.js</code> or <code>main.js</code> file. The goal is to wrap our entire app with <code>BrowserRouter</code> which will enable routing within our application.</li>
</ol>
<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.jsx'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>
<span class="hljs-keyword">import</span> { BrowserRouter <span class="hljs-keyword">as</span> Router, Routes, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</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">Router</span>&gt;</span>
      <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">App</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">Router</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">React.StrictMode</span>&gt;</span></span>,
)
</code></pre>
<ol start="6">
<li>Now in <code>App.js</code>, we're going to complete the final step of our configuration. We'll import our components, and some features from React-Router-DOM and render our components. By using <code>useLocation</code> feature from React-Router-DOM, we can set the current location of the routes by setting the key to the current path.</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>
<span class="hljs-keyword">import</span> { Routes, Route, useLocation } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>
<span class="hljs-keyword">import</span> NavBar <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/NavBar'</span>;
<span class="hljs-keyword">import</span> Home <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Home'</span>;
<span class="hljs-keyword">import</span> Projects <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Projects'</span>;
<span class="hljs-keyword">import</span> About <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/About'</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> location = useLocation();
  <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">NavBar</span> /&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">AnimatePresence</span> <span class="hljs-attr">mode</span>=<span class="hljs-string">'wait'</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span> <span class="hljs-attr">location</span>=<span class="hljs-string">{location}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{location.pathname}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">index</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Home</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">'/projects'</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Projects</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">'/about'</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">About</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">AnimatePresence</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>
<ol start="7">
<li>Now we can add our styling in <code>App.css</code>:</li>
</ol>
<pre><code class="lang-css">* {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">box-sizing</span>: border-box;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Fira Sans Condensed"</span>, sans-serif;
}

<span class="hljs-selector-tag">html</span>,
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Fira Sans Condensed"</span>, sans-serif;
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgb</span>(<span class="hljs-number">0</span>, <span class="hljs-number">162</span>, <span class="hljs-number">255</span>);
}

<span class="hljs-selector-class">.nav</span> {
  <span class="hljs-attribute">position</span>: fixed;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: space-between;
}

<span class="hljs-selector-class">.nav-links</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-class">.logo</span>, <span class="hljs-selector-class">.nav-item</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">2em</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">400</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.5vw</span>;
}

<span class="hljs-selector-tag">h1</span>{
  <span class="hljs-attribute">width</span>: <span class="hljs-number">80%</span>;
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">50%</span>, -<span class="hljs-number">50%</span>);
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">500</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">10vw</span>;
  <span class="hljs-attribute">line-height</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">text-transform</span>: uppercase;
}

<span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">text-decoration</span>: none;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">500</span>;
}
</code></pre>
<ol start="8">
<li>After following all the steps your app should look like this:</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Annotation-2024-06-14-200041.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>styled webpage without animation</em></p>
<h2 id="heading-how-to-create-transitions-using-framer-motion">How to Create Transitions Using Framer Motion</h2>
<p>Finally let's create our animation for transitions between pages.</p>
<ol>
<li><p>Create a file in components named <code>Box.jsx</code> and <code>import motion from framer-motion</code>.</p>
</li>
<li><p>We can then return two divs, with <code>classNames</code> of <code>slide-in</code> and <code>slide-out</code> one for sliding in and another for sliding out.</p>
</li>
<li><p>We insert our animation in these divs with the help of framer-motion:</p>
</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { motion } <span class="hljs-keyword">from</span> <span class="hljs-string">"framer-motion"</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">Box</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">motion.div</span>
        <span class="hljs-attr">className</span>=<span class="hljs-string">"slide-in"</span>
        <span class="hljs-attr">initial</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">scaleY:</span> <span class="hljs-attr">0</span> }}
        <span class="hljs-attr">animate</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">scaleY:</span> <span class="hljs-attr">0</span> }}
        <span class="hljs-attr">exit</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">scaleY:</span> <span class="hljs-attr">1</span> }}
        <span class="hljs-attr">transition</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">duration:</span> <span class="hljs-attr">1</span>, <span class="hljs-attr">ease:</span> [<span class="hljs-attr">0.22</span>, <span class="hljs-attr">1</span>, <span class="hljs-attr">0.36</span>, <span class="hljs-attr">1</span>] }}
     /&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">motion.div</span>
     <span class="hljs-attr">className</span>=<span class="hljs-string">"slide-out"</span>
        <span class="hljs-attr">initial</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">scaleY:</span> <span class="hljs-attr">1</span> }}
        <span class="hljs-attr">animate</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">scaleY:</span> <span class="hljs-attr">0</span> }}
        <span class="hljs-attr">exit</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">scaleY:</span> <span class="hljs-attr">0</span> }}
        <span class="hljs-attr">transition</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">duration:</span> <span class="hljs-attr">1</span>, <span class="hljs-attr">ease:</span> [<span class="hljs-attr">0.22</span>, <span class="hljs-attr">1</span>, <span class="hljs-attr">0.36</span>, <span class="hljs-attr">1</span>] }}
     /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<ol start="4">
<li>Next, we add our styling in our CSS file for <code>slide-in</code> and <code>slide-out</code> in our App.css</li>
</ol>
<pre><code class="lang-css"><span class="hljs-selector-class">.slide-in</span> {
  <span class="hljs-attribute">position</span>: fixed;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#0f0f0f</span>;
  <span class="hljs-attribute">transform-origin</span>: bottom;
}

<span class="hljs-selector-class">.slide-out</span> {
  <span class="hljs-attribute">position</span>: fixed;
  <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#0f0f0f</span>;
  <span class="hljs-attribute">transform-origin</span>: top;
}
</code></pre>
<ol start="5">
<li>Finally, the last step is to use <code>AnimatePresence</code> from framer-motion in our <code>App.js</code> file and wrap the entire App in <code>AnimatePresence</code> and set the mode as wait. If you want to learn more about a <code>AnimatePresence</code> visit the framer-motion docs.</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>
<span class="hljs-keyword">import</span> { Routes, Route, useLocation } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router-dom'</span>
<span class="hljs-keyword">import</span> NavBar <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/NavBar'</span>;
<span class="hljs-keyword">import</span> Home <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Home'</span>;
<span class="hljs-keyword">import</span> Projects <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Projects'</span>;
<span class="hljs-keyword">import</span> About <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/About'</span>;
<span class="hljs-keyword">import</span> { AnimatePresence } <span class="hljs-keyword">from</span> <span class="hljs-string">'framer-motion'</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> location = useLocation();
  <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">NavBar</span> /&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">AnimatePresence</span> <span class="hljs-attr">mode</span>=<span class="hljs-string">'wait'</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span> <span class="hljs-attr">location</span>=<span class="hljs-string">{location}</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{location.pathname}</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">index</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Home</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">'/projects'</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Projects</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">'/about'</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">About</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">AnimatePresence</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>
<ol start="6">
<li>Finally, our work should look the same as the video below:</li>
</ol>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/Sb1txpdycpA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Creating multi-page animations with Framer Motion and React-Router-Dom enhances user experience by providing smooth transitions.</p>
<p>This integration leverages the power of Framer Motion's animation capabilities with React-Router-Dom's routing features, resulting in dynamic, interactive web applications.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is the Virtual DOM in React? ]]>
                </title>
                <description>
                    <![CDATA[ As web applications become more complex, managing updates to the user interface becomes a challenging task. This is where the Virtual DOM (Document Object Model) comes into play – particularly in React, the leading JavaScript library for building use... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-the-virtual-dom-in-react/</link>
                <guid isPermaLink="false">66bc4d2973c9920bb20c0e0c</guid>
                
                    <category>
                        <![CDATA[ DOM ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ virtual dom ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Matéu.sh ]]>
                </dc:creator>
                <pubDate>Wed, 05 Jun 2024 14:51:11 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/Virtual-DOM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As web applications become more complex, managing updates to the user interface becomes a challenging task. This is where the Virtual DOM (Document Object Model) comes into play – particularly in React, the leading JavaScript library for building user interfaces.</p>
<p>The virtual DOM is a lightweight copy of the real DOM that allows React to manage changes more efficiently by minimizing the direct manipulation required on the real DOM. This process significantly enhances the performance of web apps.</p>
<p>Understanding the virtual DOM is essential for developers who want to get the best out of React. It plays a key role in how React updates the UI, ensuring that changes are applied quickly without unnecessary re-renders.  </p>
<p>In this article, you'll learn:</p>
<ul>
<li>What the virtual DOM is and how it works</li>
<li>How the virtual DOM compares to the real DOM</li>
<li>Benefits of using the virtual DOM</li>
<li>How React uses the virtual DOM</li>
<li>How the virtual DOM compares to the shadow DOM</li>
<li>Common misconceptions about the virtual DOM</li>
</ul>
<h2 id="heading-what-is-the-virtual-dom-and-how-does-it-work">What Is the Virtual DOM and How Does It Work?</h2>
<p>The virtual DOM is an in-memory representation of the real DOM elements. Instead of interacting directly with the real DOM, which can be slow and costly in terms of performance, React creates a virtual representation of the UI components. This virtual representation is a lightweight JavaScript object that mirrors the structure of the real DOM.</p>
<p>Here's a step-by-step process of how the virtual DOM works:</p>
<ol>
<li><strong>Step 1 – Initial Rendering</strong>: when the app starts, the entire UI is represented as a Virtual DOM. React elements are created and rendered into the virtual structure.</li>
<li><strong>Step 2 – State and Props Changes</strong>: as the states and props change in the app, React re-renders the affected components in the virtual DOM. These changes do not immediately impact the real DOM.</li>
<li><strong>Step 3 – Comparison Using Diff Algorithm</strong>: React then uses a <strong>diffing algorithm</strong> to compare the current version of the Virtual DOM with the previous version. This process identifies the differences (or "diffs") between the two versions.</li>
<li><strong>Step 4 – Reconciliation Process</strong>: based on the differences identified, React determines the most efficient way to update the real DOM. Only the parts of the real DOM that need to be updated are changed, rather than re-rendering the entire UI. This selective updating is quick and performant.</li>
<li><strong>Step 5 – Update to the Real DOM</strong>: finally, React applies the necessary changes to the real DOM. This might involve adding, removing, or updating elements based on the differences detected in step 3.</li>
</ol>
<p>For example, let's say we have the following counter functionality in the <code>App</code> component:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { 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">App</span>(<span class="hljs-params"></span>) </span>{
 <span class="hljs-keyword">const</span> [count, setCount] = useState(<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">h1</span>&gt;</span>Counter: {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">{()</span> =&gt;</span> setCount(count + 1)}&gt;Increment<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> App;
</code></pre>
<p>The virtual DOM representation will look like this:</p>
<pre><code class="lang-json">{
 <span class="hljs-attr">"type"</span>: <span class="hljs-string">"div"</span>,
 <span class="hljs-attr">"props"</span>: {},
 <span class="hljs-attr">"children"</span>: [
   {
     <span class="hljs-attr">"type"</span>: <span class="hljs-string">"h1"</span>,
     <span class="hljs-attr">"props"</span>: {},
     <span class="hljs-attr">"children"</span>: [
       {
         <span class="hljs-attr">"type"</span>: <span class="hljs-string">"TEXT_ELEMENT"</span>,
         <span class="hljs-attr">"props"</span>: {
           <span class="hljs-attr">"nodeValue"</span>: <span class="hljs-string">"Counter: 0"</span>
         }
       }
     ]
   },
   {
     <span class="hljs-attr">"type"</span>: <span class="hljs-string">"button"</span>,
     <span class="hljs-attr">"props"</span>: {
       <span class="hljs-attr">"onClick"</span>: <span class="hljs-string">"setCount(count + 1)"</span>
     },
     <span class="hljs-attr">"children"</span>: [
       {
         <span class="hljs-attr">"type"</span>: <span class="hljs-string">"TEXT_ELEMENT"</span>,
         <span class="hljs-attr">"props"</span>: {
           <span class="hljs-attr">"nodeValue"</span>: <span class="hljs-string">"Increment"</span>
         }
       }
     ]
   }
 ]
}
</code></pre>
<p>When the <code>Increase</code> button is clicked once, only the <code>h1</code> element is changed:</p>
<pre><code class="lang-json">{
 <span class="hljs-attr">"type"</span>: <span class="hljs-string">"h1"</span>,
 <span class="hljs-attr">"props"</span>: {},
 <span class="hljs-attr">"children"</span>: [
   {
     <span class="hljs-attr">"type"</span>: <span class="hljs-string">"TEXT_ELEMENT"</span>,
     <span class="hljs-attr">"props"</span>: {
       <span class="hljs-attr">"nodeValue"</span>: <span class="hljs-string">"Counter: 1"</span>
     }
   }
 ]
}
</code></pre>
<h2 id="heading-comparing-the-virtual-dom-to-the-real-dom">Comparing the Virtual DOM to the Real DOM</h2>
<p>To see the advantages of the virtual DOM, it's important to understand how it differs from the real DOM. The real DOM and the virtual DOM serve similar purposes but operate in distinct ways with significant implications for performance and efficiency.</p>
<p>The real DOM is a built-in standard interface in browsers that represents and interacts with HTML elements, from <code>Doctype</code> declaration and the root <code>html</code> element to every other element in it.</p>
<p>This real DOM represents the whole HTML document as a tree structure and allows JavaScript to manipulate and change HTML documents. Sometimes when those changes occur, the whole document might re-render.</p>
<p>This is in contrast to the virtual DOM, which uses a <strong>diff algorithm</strong> to compare the current and previous versions of updates to the DOM. It only re-renders the parts of the UI that have changed, instead of the whole thing.</p>
<h2 id="heading-benefits-of-using-the-virtual-dom-in-web-development">Benefits of Using the Virtual DOM in Web Development</h2>
<h3 id="heading-simplified-development">Simplified Development</h3>
<p>The Virtual DOM lets you write code in a more declarative style. This means that instead of writing detailed instructions on how to update the UI, you can simply describe what the UI should look like, and React takes care of the rest. This is made possible by React's declarative syntax and its component-based architecture.</p>
<h3 id="heading-improved-performance">Improved Performance</h3>
<p>One of the major advantages of using the virtual DOM is the significant performance improvement it offers. Direct manipulation of the real DOM is slow and can lead to performance issues, especially in complex applications.</p>
<h3 id="heading-enhanced-user-experience">Enhanced User Experience</h3>
<p>The Virtual DOM contributes to a better UX by ensuring that UI updates are smooth, responsive, and without full-page refreshes. Users are less likely to experience lag or jank, resulting in a more seamless interaction with the app.</p>
<h3 id="heading-cross-platform-development">Cross-platform Development</h3>
<p>The principles of the Virtual DOM are not limited to web development only. React Native – a version of React for building cross-platform mobile apps – uses a similar approach. This increases productivity and reduces development time because you can reuse code across web and mobile platforms</p>
<h2 id="heading-common-misconceptions-about-the-virtual-dom">Common Misconceptions About the Virtual DOM</h2>
<p>There are a few misconceptions about the virtual DOM. Let's look at five of these misconceptions and the realities of each of them.</p>
<h3 id="heading-the-virtual-dom-is-a-browser-feature">The Virtual DOM Is a Browser Feature</h3>
<p><strong>Reality</strong>: the virtual DOM is an abstraction implemented by React, not a browser feature. Browsers have the real DOM, which is the standard way to represent and interact with HTML documents. The virtual DOM exists solely in memory within React and is used to optimize updates to the real DOM.</p>
<h3 id="heading-the-virtual-dom-replaces-the-real-dom">The Virtual DOM Replaces the Real DOM</h3>
<p><strong>Reality</strong>: The virtual DOM acts as an intermediary between React and the browser, not a replacement for the real DOM. The real DOM is still what the browser uses to render the UI, but the updates to it are managed through the Virtual DOM.</p>
<h3 id="heading-react-is-the-only-library-and-framework-that-uses-the-virtual-dom">React is the Only Library and Framework that Uses the Virtual DOM</h3>
<p><strong>Reality</strong>: React only popularized the concept of the virtual DOM, it is not the only library or framework that uses it. Other frameworks like VueJS and SolidJS also use the virtual DOM to update the UI.</p>
<h3 id="heading-the-virtual-dom-solves-all-performance-problems">The Virtual DOM Solves All Performance Problems</h3>
<p><strong>Reality</strong>: The virtual DOM can significantly improve performance, but it is not a magical solution to all problems. Poor coding practices, unnecessary renders, and large component trees can still lead to performance issues.</p>
<h3 id="heading-the-virtual-dom-and-shadow-dom-are-the-same">The Virtual DOM and Shadow DOM Are the Same</h3>
<p><strong>Reality</strong>: The virtual DOM and shadow DOM are not the same thing. The virtual DOM is a lightweight copy of the Real DOM with which React optimize UI updates. On the other hand, shadow DOM is a browser technology used to encapsulate the styles and structure of web components.</p>
<h2 id="heading-real-dom-vs-virtual-dom-vs-shadow-dom">Real DOM vs Virtual DOM vs Shadow DOM</h2>
<p>Now that we've established that the virtual DOM, shadow DOM, and real DOM are not the same, let's look at the differences between the three of them.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Aspect</strong></td><td><strong>Real DOM</strong></td><td><strong>Virtual DOM</strong></td><td><strong>Shadow DOM</strong>  </td></tr>
</thead>
<tbody>
<tr>
<td><strong>Definition</strong></td><td>Standard browser API for representing and interacting with HTML documents</td><td>In-memory representation of the Real DOM</td><td>A browser technology that encapsulates and scopes DOM and style of web components  </td></tr>
<tr>
<td><strong>Flexibility</strong></td><td>Directly manipulated via JavaScript or DOM APIs</td><td>Abstracted and optimized by the framework</td><td>Limited to component boundaries</td></tr>
<tr>
<td><strong>Implementation</strong></td><td>Provided by the browser</td><td>Implemented by frameworks like React and Vue</td><td>Part of the Web Components standard, provided by the browser </td></tr>
<tr>
<td><strong>Performance</strong></td><td>Direct manipulation can be slow and cause performance issues</td><td>Already optimized for efficient updates</td><td>Provides encapsulation, reducing style conflicts </td></tr>
<tr>
<td><strong>Usage</strong></td><td>For rendering and interacting with web documents</td><td>For efficient UI updates by frameworks</td><td>For creating isolated, reusable web components</td></tr>
<tr>
<td><strong>Updates</strong></td><td>Immediate updates to the UI</td><td>Updates are batched and optimized</td><td>Updates are scoped to the component, not affecting the global DOM</td></tr>
<tr>
<td><strong>Repaints</strong></td><td>Frequent updates can cause costly repaints</td><td>Minimizes repaints by batching updates</td><td>Scoped to the component, reducing global repaints</td></tr>
<tr>
<td><strong>Use Cases</strong></td><td>General web development and document manipulation</td><td>Efficient UI updates in frameworks like React and Vue</td><td>Encapsulation of styles and structure in web components</td></tr>
</tbody>
</table>
</div><h2 id="heading-conclusion">Conclusion</h2>
<p>As you've read in this article, the Virtual DOM is a key React feature that enhances performance and efficient UI updates. With this, React can batch updates, minimize reflows and repaints, and apply changes efficiently. This makes UI updates fast and smooth, providing a better user experience in the process.</p>
<p>Understanding the Virtual DOM and how it works can help you build performant React applications.</p>
<h2 id="heading-learn-react-and-next-js">Learn React and Next JS</h2>
<p>Want to discover more cool React features like the virtual DOM? Enroll in my React 18 course on Udemy! I'll guide you through the React world by creating a cool 2048 game with animations from scratch.</p>
<p><a target="_blank" href="https://assets.mateu.sh/r/fcc-universal"><img src="https://assets.mateu.sh/assets/fcc-universal" alt="Next.js crash course on Udemy" width="600" height="400" loading="lazy"></a>  </p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
