← Back to the Build Your Homepage series
πŸš€
EPISODE 05
Components, state, and routing as used in industry

Build a Real Web App with React + Next.js

Step up from plain HTML files. Create a Next.js project, break the UI into reusable components, manage state with useState, and ship it to Vercel just like a real product team.

ReactNext.jsComponentsStateJSX
Duration
⏱ About 4 hours
Level
πŸ“Š Beginner+ (after Lessons 1–4)
Prerequisite
🎯 Lessons 1–4 (especially JavaScript basics)
OUTCOME
A Next.js app deployed on Vercel with multiple pages and components

What you'll learn

  • 1Create a Next.js project with create-next-app
  • 2Write components in JSX and compose them
  • 3Manage local component state with useState
  • 4Add routing between pages using the App Router
  • 5Deploy the app to Vercel β€” same flow as Lesson 1

1. Why React + Next.js?

  • React turns the UI into reusable components β€” write once, use everywhere
  • Next.js wraps React with routing, server features, and zero-config builds
  • Together they are the most common stack for modern web apps
  • Vercel was made by the Next.js team β€” deployment is one click

2. Set Up the Project

You need Node.js installed. Get the LTS version from https://nodejs.org.

bash
node --version    # v20.x or newer
npm --version

npx create-next-app@latest my-app
#   βœ“ Use TypeScript?            Yes
#   βœ“ Use ESLint?                Yes
#   βœ“ Use Tailwind CSS?          Yes (recommended for styling)
#   βœ“ Use App Router?            Yes
#   βœ“ Use src/ directory?        No
#   βœ“ Customize import alias?    No

cd my-app
npm run dev      # open http://localhost:3000

3. Folder Tour

text
my-app/
β”œβ”€β”€ app/                # routes live here
β”‚   β”œβ”€β”€ layout.tsx      # wraps every page (header, footer)
β”‚   β”œβ”€β”€ page.tsx        # the homepage (/)
β”‚   └── about/
β”‚       └── page.tsx    # /about
β”œβ”€β”€ public/             # static assets
β”œβ”€β”€ package.json
└── tsconfig.json

Routes are just folders

  • app/page.tsx β†’ /
  • app/about/page.tsx β†’ /about
  • app/blog/[slug]/page.tsx β†’ /blog/anything (dynamic)

4. Your First Component

tsx
// app/page.tsx
export default function HomePage() {
  return (
    <main className="p-8">
      <h1 className="text-3xl font-bold">Hello, Next.js!</h1>
      <p className="text-gray-600">My first React component.</p>
    </main>
  );
}

JSX looks like HTML inside JavaScript. Key differences: className instead of class, self-closing tags require /, expressions go in { }.

5. Components & Props

tsx
// app/components/Card.tsx
type CardProps = { title: string; description: string };

export default function Card({ title, description }: CardProps) {
  return (
    <div className="rounded-lg border p-4 shadow-sm">
      <h2 className="text-xl font-semibold">{title}</h2>
      <p className="text-gray-500">{description}</p>
    </div>
  );
}

// app/page.tsx
import Card from "./components/Card";

export default function Home() {
  return (
    <main className="p-8 grid gap-4 md:grid-cols-3">
      <Card title="HTML"       description="Structure" />
      <Card title="CSS"        description="Style" />
      <Card title="JavaScript" description="Behavior" />
    </main>
  );
}

6. State with useState

tsx
"use client";   // needed for hooks in App Router
import { useState } from "react";

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

  return (
    <div className="text-center">
      <p className="text-2xl">{count}</p>
      <button onClick={() => setCount(count + 1)}
              className="px-4 py-2 bg-blue-600 text-white rounded">
        + Increment
      </button>
    </div>
  );
}
ℹ️

App Router components are server components by default. Add "use client" at the top of files that use hooks like useState or useEffect.

7. Multiple Pages & Navigation

tsx
// app/about/page.tsx
export default function About() {
  return <main className="p-8"><h1>About me</h1></main>;
}

// app/layout.tsx β€” header lives in the shared layout
import Link from "next/link";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <nav className="p-4 border-b flex gap-4">
          <Link href="/">Home</Link>
          <Link href="/about">About</Link>
        </nav>
        {children}
      </body>
    </html>
  );
}
πŸ’‘

Use <Link> from next/link instead of <a>. It enables fast client-side navigation without full page reloads.

8. Tailwind for Styling

Tailwind gives you styling via utility classes β€” no separate CSS file needed.

tsx
<button className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
  Click me
</button>
  • px-4 py-2 β†’ padding
  • bg-blue-600 β†’ background color
  • text-white β†’ text color
  • rounded β†’ border radius
  • hover:bg-blue-700 β†’ hover state

9. Deploy to Vercel

  1. Push the project to a new GitHub repo (git init / add / commit / push)
  2. Visit Vercel β†’ Add New Project β†’ import the repo
  3. Click Deploy β€” Vercel detects Next.js automatically
  4. Your app is live at https://my-app-your-name.vercel.app

Subsequent pushes redeploy automatically β€” exactly like Lesson 1.

10. What is Next

  • You created a real Next.js project with TypeScript and Tailwind
  • You built reusable components with props
  • You managed state with useState
  • You added routing and a shared layout
  • You deployed everything to Vercel

From here on, the curriculum deepens each piece: HTML, CSS, JavaScript, then Node.js, databases, TypeScript, advanced React, and finally collaboration, accessibility, and security.

πŸ›  Mini Projects

Convert your static homepage from Lesson 2 into a Next.js project
Build a /projects page that maps over an array of project objects
Add a dark-mode toggle component using useState + localStorage
Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub β†—