Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
menu
  1. Home
  2. /Web Development
  3. /Nextjs
  4. /Client Components
Your Progress0%
0 of 70 completed

NextJS Topics

Getting Started

  • What is Next.js?
  • Next.js vs React - Key Differences
  • Creating Your First Next.js 15 Project
  • Next.js Project Structure Explained
  • App Router vs Pages Router

Routing Fundamentals

  • File-Based Routing Basics
  • Creating Pages with page.tsx
  • Dynamic Routes and Route Parameters
  • Catch-All and Optional Catch-All Routes
  • Route Groups for Organization
  • Parallel Routes
  • Intercepting Routes

Layouts and Pages

  • Understanding Layouts
  • Root Layout and Global Configuration
  • Nested Layouts
  • Templates vs Layouts
  • Loading States with loading.tsx
  • Error Handling with error.tsx

Server and Client Components

  • Understanding Server Components
  • Client Components with 'use client'
  • When to Use Server vs Client Components
  • Component Composition Patterns
  • Passing Props Between Server and Client
  • Server Component Patterns and Best Practices

Data Fetching

  • Fetching Data in Server Components
  • Parallel and Sequential Data Fetching
  • Data Fetching Patterns and Strategies
  • Caching and Revalidation
  • Revalidate and Cache Tags
  • Handling Loading and Error States in Data Fetching

Navigation and Links

  • Link Component Basics
  • useRouter Hook for Programmatic Navigation
  • usePathname and useSearchParams Hooks
  • Active Links and Navigation States
  • Redirects and Navigation Guards

Styling in Next.js

  • CSS Modules in Next.js
  • Tailwind CSS Setup and Configuration
  • Global Styles and CSS Variables
  • Next.js Font Optimization

Images and Media

  • Next.js Image Component Basics
  • Image Optimization and Best Practices
  • Working with Static Assets

Forms and Data Mutations

  • Understanding Server Actions
  • Form Handling with Server Actions
  • Form Validation and Error Handling
  • useFormStatus and useFormState Hooks
  • Revalidating Data After Mutations
  • Optimistic Updates

Metadata and SEO

  • Static Metadata Configuration
  • Dynamic Metadata Generation
  • Open Graph and Social Media Cards
  • Sitemap and Robots.txt

API Routes and Route Handlers

  • Route Handlers Introduction
  • GET and POST Request Handlers
  • Dynamic API Routes
  • Request and Response Objects
  • API Error Handling and Status Codes

Middleware and Advanced Features

  • Introduction to Middleware
  • Authentication with Middleware
  • Environment Variables and Configuration
  • Streaming and Suspense
  • Not Found and Global Error Pages

Deployment and Optimization

  • Understanding Static and Dynamic Rendering
  • generateStaticParams for Static Generation
  • Build and Production Optimization
  • Deploying to Vercel
  • Alternative Deployment Options
  • Performance Monitoring and Analytics

Real-World Projects

  • Project 1: E-commerce Product Catalog
  • Project 2: Dashboard with Authentication

Client Components with 'use client'

Adding interactivity with the 'use client' directive

Server Components are great for static content and data fetching, but what about buttons, forms, and animations? That's where Client Components come in. By adding the 'use client' directive at the top of a file, you tell Next.js "this component needs to run in the browser." Client Components can use hooks, handle events, and access browser APIs—everything you need for interactivity. Let's learn when and how to use them effectively!

What Are Client Components?

Client Components are React components that run in the browser:

  • Marked with 'use client': Directive at top of file
  • Include JavaScript: Sent to client bundle
  • Full React features: Hooks, event handlers, browser APIs
  • Interactive: Enable user interaction and state
  • Hydrated: Start as HTML, then become interactive

Client Components in Your App

Client Components are marked with 'use client' directive

appImportant

Select a file or folder to see details

The 'use client' Directive

'use client' is a module directive, not a React API. It tells the bundler: "this module and its imports need to be in the client bundle."

Creating Your First Client Component

Basic Client Component

components/Counter.tsx
'use client'; // This makes it a Client Component!

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
}

// ✅ Has 'use client' directive
// ✅ Uses useState hook
// ✅ Has onClick event handler
// ✅ Sent to client bundle

Without 'use client' (Won't Work!)

components/Counter.tsx
// ❌ NO 'use client' - This will ERROR!
import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0); // ❌ Error: Server Components can't use hooks

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}> {/* ❌ Error: No event handlers */}
        Increment
      </button>
    </div>
  );
}

// ❌ Missing 'use client'
// ❌ Treated as Server Component
// ❌ Can't use hooks or event handlers

⚡ Directive Placement

'use client' must be at the very top of the file, before any imports. It's the first thing in your file.

What Can Client Components Do?

✅ Client Components CAN:

  • Use React hooks - useState, useEffect, useContext, etc.
  • Handle events - onClick, onChange, onSubmit, etc.
  • Access browser APIs - window, localStorage, geolocation, etc.
  • Use Context - create and consume Context providers
  • Use browser-only libraries - chart libraries, UI libraries
  • Track user interactions - analytics, click tracking

❌ Client Components CANNOT:

  • Be async functions - no async/await in component
  • Access backend directly - must use API routes
  • Use server-only APIs - no fs, database, etc.
  • Import Server Components - can only pass as children
TYPESCRIPT
'use client';

import { useState, useEffect } from 'react';

// ✅ GOOD: Client Component doing client things
export function GoodClientComponent() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    // Access browser API
    localStorage.setItem('count', count.toString());
  }, [count]);
  
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

// ❌ BAD: Client Component trying to be async
export async function BadClientComponent() { // ❌ Can't be async!
  const data = await fetch('...');
  return <div>{data}</div>;
}

// ✅ GOOD: Use hooks for async operations
export function GoodAsyncClientComponent() {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(r => r.json())
      .then(setData);
  }, []);
  
  return <div>{data?.title}</div>;
}

Common Client Component Use Cases

1. Interactive Buttons

components/LikeButton.tsx
'use client';

import { useState } from 'react';

export default function LikeButton({ postId }: { postId: string }) {
  const [liked, setLiked] = useState(false);
  const [count, setCount] = useState(0);

  const handleLike = async () => {
    setLiked(!liked);
    setCount(liked ? count - 1 : count + 1);
    
    // Call API to save like
    await fetch('/api/like', {
      method: 'POST',
      body: JSON.stringify({ postId, liked: !liked }),
    });
  };

  return (
    <button
      onClick={handleLike}
      className={liked ? 'text-red-500' : 'text-gray-500'}
    >
      ❤️ {count} Likes
    </button>
  );
}

2. Forms with Validation

components/ContactForm.tsx
'use client';

import { useState } from 'react';

export default function ContactForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: '',
  });
  const [errors, setErrors] = useState<Record<string, string>>({});
  const [isSubmitting, setIsSubmitting] = useState(false);

  const validate = () => {
    const newErrors: Record<string, string> = {};
    
    if (!formData.name) newErrors.name = 'Name is required';
    if (!formData.email) newErrors.email = 'Email is required';
    if (!/S+@S+.S+/.test(formData.email)) {
      newErrors.email = 'Email is invalid';
    }
    if (!formData.message) newErrors.message = 'Message is required';
    
    return newErrors;
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    const newErrors = validate();
    if (Object.keys(newErrors).length > 0) {
      setErrors(newErrors);
      return;
    }
    
    setIsSubmitting(true);
    
    try {
      await fetch('/api/contact', {
        method: 'POST',
        body: JSON.stringify(formData),
      });
      
      alert('Message sent!');
      setFormData({ name: '', email: '', message: '' });
    } catch (error) {
      alert('Failed to send message');
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <div>
        <input
          type="text"
          value={formData.name}
          onChange={(e) => setFormData({ ...formData, name: e.target.value })}
          placeholder="Your name"
          className="w-full px-4 py-2 border rounded"
        />
        {errors.name && <p className="text-red-500 text-sm">{errors.name}</p>}
      </div>
      
      <div>
        <input
          type="email"
          value={formData.email}
          onChange={(e) => setFormData({ ...formData, email: e.target.value })}
          placeholder="Your email"
          className="w-full px-4 py-2 border rounded"
        />
        {errors.email && <p className="text-red-500 text-sm">{errors.email}</p>}
      </div>
      
      <div>
        <textarea
          value={formData.message}
          onChange={(e) => setFormData({ ...formData, message: e.target.value })}
          placeholder="Your message"
          className="w-full px-4 py-2 border rounded"
          rows={4}
        />
        {errors.message && <p className="text-red-500 text-sm">{errors.message}</p>}
      </div>
      
      <button
        type="submit"
        disabled={isSubmitting}
        className="px-6 py-3 bg-blue-600 text-white rounded disabled:opacity-50"
      >
        {isSubmitting ? 'Sending...' : 'Send Message'}
      </button>
    </form>
  );
}

3. Search with Live Results

components/SearchBar.tsx
'use client';

import { useState, useEffect } from 'react';

interface SearchResult {
  id: string;
  title: string;
  description: string;
}

export default function SearchBar() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState<SearchResult[]>([]);
  const [isSearching, setIsSearching] = useState(false);

  useEffect(() => {
    if (!query) {
      setResults([]);
      return;
    }

    const searchTimeout = setTimeout(async () => {
      setIsSearching(true);
      
      try {
        const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
        const data = await res.json();
        setResults(data.results);
      } catch (error) {
        console.error('Search failed:', error);
      } finally {
        setIsSearching(false);
      }
    }, 300); // Debounce: wait 300ms after user stops typing

    return () => clearTimeout(searchTimeout);
  }, [query]);

  return (
    <div className="relative">
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
        className="w-full px-4 py-2 border rounded"
      />
      
      {isSearching && (
        <div className="absolute right-3 top-3">
          <div className="animate-spin h-5 w-5 border-2 border-blue-600 rounded-full border-t-transparent" />
        </div>
      )}
      
      {results.length > 0 && (
        <div className="absolute w-full mt-2 bg-white border rounded-lg shadow-lg">
          {results.map(result => (
            
              key={result.id}
              href={`/search/${result.id}`}
              className="block p-4 hover:bg-gray-50"
            >
              <h3 className="font-semibold">{result.title}</h3>
              <p className="text-sm text-gray-600">{result.description}</p>
            </a>
          ))}
        </div>
      )}
    </div>
  );
}

4. Modal Dialog

components/Modal.tsx
'use client';

import { useEffect } from 'react';

interface ModalProps {
  isOpen: boolean;
  onClose: () => void;
  children: React.ReactNode;
}

export default function Modal({ isOpen, onClose, children }: ModalProps) {
  useEffect(() => {
    // Close on escape key
    const handleEscape = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose();
    };
    
    if (isOpen) {
      document.addEventListener('keydown', handleEscape);
      // Prevent body scroll
      document.body.style.overflow = 'hidden';
    }
    
    return () => {
      document.removeEventListener('keydown', handleEscape);
      document.body.style.overflow = 'unset';
    };
  }, [isOpen, onClose]);

  if (!isOpen) return null;

  return (
    <div
      className="fixed inset-0 z-50 flex items-center justify-center"
      onClick={onClose}
    >
      {/* Backdrop */}
      <div className="absolute inset-0 bg-black/50" />
      
      {/* Modal */}
      <div
        className="relative bg-white rounded-lg p-6 max-w-md w-full mx-4 shadow-xl"
        onClick={(e) => e.stopPropagation()}
      >
        {/* Close button */}
        <button
          onClick={onClose}
          className="absolute top-4 right-4 text-gray-500 hover:text-gray-700"
        >
          ✕
        </button>
        
        {children}
      </div>
    </div>
  );
}

5. Dark Mode Toggle

components/ThemeToggle.tsx
'use client';

import { useState, useEffect } from 'react';

export default function ThemeToggle() {
  const [isDark, setIsDark] = useState(false);

  useEffect(() => {
    // Check localStorage on mount
    const savedTheme = localStorage.getItem('theme');
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    
    const shouldBeDark = savedTheme === 'dark' || (!savedTheme && prefersDark);
    setIsDark(shouldBeDark);
    
    // Apply theme
    document.documentElement.classList.toggle('dark', shouldBeDark);
  }, []);

  const toggleTheme = () => {
    const newIsDark = !isDark;
    setIsDark(newIsDark);
    
    // Save to localStorage
    localStorage.setItem('theme', newIsDark ? 'dark' : 'light');
    
    // Apply theme
    document.documentElement.classList.toggle('dark', newIsDark);
  };

  return (
    <button
      onClick={toggleTheme}
      className="p-2 rounded-lg bg-gray-200 dark:bg-gray-700"
      aria-label="Toggle theme"
    >
      {isDark ? '🌙' : '☀️'}
    </button>
  );
}

Using Client Components with Server Components

The most common pattern: Server Component fetches data, Client Component adds interactivity:

Server Component (Page)

app/blog/[slug]/page.tsx
import { LikeButton } from '@/components/LikeButton';
import { CommentForm } from '@/components/CommentForm';

async function getPost(slug: string) {
  const res = await fetch(`https://api.example.com/posts/${slug}`);
  return res.json();
}

// Server Component - fetches data
export default async function BlogPostPage({
  params,
}: {
  params: { slug: string };
}) {
  const post = await getPost(params.slug);

  return (
    <article>
      {/* Server-rendered content */}
      <h1>{post.title}</h1>
      <p className="text-gray-600">By {post.author}</p>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
      
      {/* Client Component for interactivity */}
      <LikeButton postId={post.id} initialLikes={post.likes} />
      
      {/* Another Client Component */}
      <CommentForm postId={post.id} />
    </article>
  );
}

// ✅ Server Component fetches data
// ✅ Client Components add interactivity
// ✅ Best of both worlds!

Client Component (LikeButton)

components/LikeButton.tsx
'use client';

import { useState } from 'react';

export function LikeButton({
  postId,
  initialLikes,
}: {
  postId: string;
  initialLikes: number;
}) {
  const [likes, setLikes] = useState(initialLikes);
  const [liked, setLiked] = useState(false);

  const handleLike = async () => {
    const newLiked = !liked;
    setLiked(newLiked);
    setLikes(newLiked ? likes + 1 : likes - 1);

    await fetch('/api/like', {
      method: 'POST',
      body: JSON.stringify({ postId, liked: newLiked }),
    });
  };

  return (
    <button
      onClick={handleLike}
      className={`flex items-center gap-2 px-4 py-2 rounded ${
        liked ? 'bg-red-100 text-red-600' : 'bg-gray-100'
      }`}
    >
      ❤️ {likes} Likes
    </button>
  );
}

Perfect Combination

This pattern gives you the best of both worlds:

  • Server Component fetches data (fast, SEO-friendly)
  • Client Component adds interactivity (buttons, forms)
  • Most of your page is Server Components (small bundle)
  • Only interactive parts are Client Components

Client Component Boundary Rules

Rule 1: Server Components Can Import Client Components

TYPESCRIPT
// ✅ ALLOWED: Server Component importing Client Component
import { Counter } from './Counter'; // Has 'use client'

export default async function Page() {
  const data = await getData();
  
  return (
    <div>
      <h1>{data.title}</h1>
      <Counter /> {/* Client Component */}
    </div>
  );
}

Rule 2: Client Components CANNOT Import Server Components

TYPESCRIPT
'use client';

// ❌ ERROR: Client Component cannot import Server Component
import { BlogPost } from './BlogPost'; // Server Component

export function MyComponent() {
  return <BlogPost />; // ❌ Won't work!
}

Rule 3: But Client Components Can Receive Server Components as Children

TYPESCRIPT
// Server Component
async function Page() {
  const post = await getPost();
  
  return (
    <ClientWrapper>
      {/* Pass Server Component as children */}
      <BlogPost post={post} /> {/* Server Component */}
    </ClientWrapper>
  );
}

// Client Component
'use client';
export function ClientWrapper({ children }) {
  return (
    <div className="wrapper">
      {children} {/* Server Component rendered as child */}
    </div>
  );
}

Rule 4: 'use client' Marks the Boundary

TYPESCRIPT
// File A: Has 'use client'
'use client';
import { ComponentB } from './ComponentB';

export function ComponentA() {
  return <ComponentB />;
}

// File B: No 'use client'
// BUT becomes Client Component because imported by Client Component!
export function ComponentB() {
  return <div>I'm also a Client Component now</div>;
}

// Once you cross the 'use client' boundary,
// everything below is a Client Component!

Client Component Best Practices

1. Use Client Components Sparingly

Only add 'use client' where you actually need interactivity. Keep as much as possible as Server Components.

TYPESCRIPT
// ❌ BAD: Entire page is Client Component
'use client';

export default function Page() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <Header /> {/* Doesn't need to be client */}
      <Content /> {/* Doesn't need to be client */}
      <button onClick={() => setCount(count + 1)}>
        {count}
      </button>
    </div>
  );
}

// ✅ GOOD: Only interactive part is Client Component
export default function Page() {
  return (
    <div>
      <Header /> {/* Server Component */}
      <Content /> {/* Server Component */}
      <Counter /> {/* Client Component */}
    </div>
  );
}

2. Push 'use client' Down

Move the 'use client' directive to the lowest component that needs it:

TYPESCRIPT
// ❌ BAD: Too high up
'use client'; // Entire file is client now

export function ProductPage({ product }) {
  return (
    <div>
      <ProductDetails product={product} /> {/* Now client */}
      <ProductImages images={product.images} /> {/* Now client */}
      <AddToCartButton productId={product.id} /> {/* Needs to be client */}
    </div>
  );
}

// ✅ GOOD: Only the button needs to be client
// ProductPage.tsx (Server Component)
export function ProductPage({ product }) {
  return (
    <div>
      <ProductDetails product={product} /> {/* Server */}
      <ProductImages images={product.images} /> {/* Server */}
      <AddToCartButton productId={product.id} /> {/* Client */}
    </div>
  );
}

// AddToCartButton.tsx
'use client';
export function AddToCartButton({ productId }) {
  // Only this component is Client Component
}

3. Pass Data as Props, Not Context

TYPESCRIPT
// ❌ BAD: Using Context from Server Component
// Won't work - Server Components can't use Context

// ✅ GOOD: Pass data as props
// Server Component
async function Page() {
  const user = await getUser();
  
  return (
    <ClientComponent user={user} /> {/* Pass as prop */}
  );
}

// Client Component
'use client';
export function ClientComponent({ user }) {
  return <div>Welcome, {user.name}!</div>;
}

4. Minimize Client Bundle Size

TYPESCRIPT
'use client';

// ❌ BAD: Heavy import in Client Component
import _ from 'lodash'; // 70KB!

export function MyComponent() {
  const sorted = _.sortBy(data, 'name');
  return <div>{sorted}</div>;
}

// ✅ GOOD: Use lightweight alternative
export function MyComponent() {
  const sorted = data.sort((a, b) => a.name.localeCompare(b.name));
  return <div>{sorted}</div>;
}

// Or extract heavy work to Server Component

5. Use Server Actions for Mutations

TYPESCRIPT
// Server Action
'use server';
export async function createPost(formData: FormData) {
  const title = formData.get('title');
  await db.posts.create({ title });
}

// Client Component using Server Action
'use client';
import { createPost } from './actions';

export function PostForm() {
  return (
    <form action={createPost}>
      <input name="title" />
      <button type="submit">Create</button>
    </form>
  );
}

// ✅ Form in Client Component
// ✅ Mutation on server
// ✅ No API route needed

Complete Practical Example

Interactive Search Bar (Client Component)

A complete search bar with debouncing and live results

SearchBar.tsx

Output Preview

Click "Run Code" to see the output

Key Takeaways

  • Add 'use client' at top of file - before any imports
  • Client Components enable interactivity - hooks, events, browser APIs
  • Cannot be async - use useEffect for data fetching
  • Server Components can import Client Components - common pattern
  • Client Components cannot import Server Components - but can receive as children
  • Use sparingly - only where interactivity is needed
  • Push 'use client' down - keep as much as Server Components
  • Client Components are added to bundle - minimize size

What's Next?

You now understand both Server and Client Components! But when should you use each? The next lesson provides a decision guide to help you choose between Server and Client Components for any situation.

We'll cover specific scenarios, common patterns, and a decision tree to make the choice clear. You'll learn to architect your application for optimal performance while maintaining the interactivity users expect.

🎯 Start with Server, Add Client

The golden rule: start with Server Components for everything. Only add 'use client' when you need interactivity. This approach gives you the best performance by default!

Test Your Understanding

Question 1 of 4

What makes a component a Client Component?

Master Client Components in Next.js! Learn when and how to add interactivity with 'use client'.

Previous
Understanding Server Components
Next
When to Use Server vs Client Components

Master Next.js Component Architecture

Join 2,000+ developers building optimized Next.js apps. Get the next lesson on choosing between Server and Client Components - 100% FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

NextJS Tutorials

0 of 70 completed

Your Progress0%

Topics

Getting Started

  • What is Next.js?
  • Next.js vs React - Key Differences
  • Creating Your First Next.js 15 Project
  • Next.js Project Structure Explained
  • App Router vs Pages Router

Routing Fundamentals

  • File-Based Routing Basics
  • Creating Pages with page.tsx
  • Dynamic Routes and Route Parameters
  • Catch-All and Optional Catch-All Routes
  • Route Groups for Organization
  • Parallel Routes
  • Intercepting Routes

Layouts and Pages

  • Understanding Layouts
  • Root Layout and Global Configuration
  • Nested Layouts
  • Templates vs Layouts
  • Loading States with loading.tsx
  • Error Handling with error.tsx

Server and Client Components

  • Understanding Server Components
  • Client Components with 'use client'
  • When to Use Server vs Client Components
  • Component Composition Patterns
  • Passing Props Between Server and Client
  • Server Component Patterns and Best Practices

Data Fetching

  • Fetching Data in Server Components
  • Parallel and Sequential Data Fetching
  • Data Fetching Patterns and Strategies
  • Caching and Revalidation
  • Revalidate and Cache Tags
  • Handling Loading and Error States in Data Fetching

Navigation and Links

  • Link Component Basics
  • useRouter Hook for Programmatic Navigation
  • usePathname and useSearchParams Hooks
  • Active Links and Navigation States
  • Redirects and Navigation Guards

Styling in Next.js

  • CSS Modules in Next.js
  • Tailwind CSS Setup and Configuration
  • Global Styles and CSS Variables
  • Next.js Font Optimization

Images and Media

  • Next.js Image Component Basics
  • Image Optimization and Best Practices
  • Working with Static Assets

Forms and Data Mutations

  • Understanding Server Actions
  • Form Handling with Server Actions
  • Form Validation and Error Handling
  • useFormStatus and useFormState Hooks
  • Revalidating Data After Mutations
  • Optimistic Updates

Metadata and SEO

  • Static Metadata Configuration
  • Dynamic Metadata Generation
  • Open Graph and Social Media Cards
  • Sitemap and Robots.txt

API Routes and Route Handlers

  • Route Handlers Introduction
  • GET and POST Request Handlers
  • Dynamic API Routes
  • Request and Response Objects
  • API Error Handling and Status Codes

Middleware and Advanced Features

  • Introduction to Middleware
  • Authentication with Middleware
  • Environment Variables and Configuration
  • Streaming and Suspense
  • Not Found and Global Error Pages

Deployment and Optimization

  • Understanding Static and Dynamic Rendering
  • generateStaticParams for Static Generation
  • Build and Production Optimization
  • Deploying to Vercel
  • Alternative Deployment Options
  • Performance Monitoring and Analytics

Real-World Projects

  • Project 1: E-commerce Product Catalog
  • Project 2: Dashboard with Authentication
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo