React - Next.js and Meta-Frameworks
Once you have some mastery of React, I STRONGLY ADVISE you to move on to a meta-framework. Next.js, Astro, Remix... whichever one, it will revolutionize the way you develop!
Why Meta-Frameworks?
React Alone is Limited
React is just a library for creating interfaces. But for a real web application, you need:
- 🗺️ Routing: managing pages and navigation
- ⚡ Server-Side Rendering (SSR): SEO and performance
- 🏗️ Static Site Generation (SSG): ultra-fast sites
- 🖼️ Image optimization: modern formats, lazy loading
- 📦 Bundle optimization: automatic code splitting
- 🔧 Configuration: Webpack, Babel, TypeScript...
React + Vite = Not Enough for Production
// ❌ With classic React/Vite - you have to do everything manually
function App() {
return (
<div>
{/* How do you do routing? */}
{/* How do you optimize images? */}
{/* How do you manage SEO? */}
{/* How do you do SSR? */}
</div>
)
}
// ✅ With Next.js - everything is automatic!
export default function HomePage() {
return (
<div>
<Head>
<title>My awesome page - Automatic SEO!</title>
</Head>
<Image
src="/photo.jpg"
alt="Automatically optimized photo"
width={500}
height={300}
/>
</div>
)
}
// Automatic SSG with this function
export async function getStaticProps() {
const data = await fetch('https://api.example.com/data')
return { props: { data } }
}
Next.js - The Boss of Meta-Frameworks
Ultra Simple Setup
npx create-next-app@latest my-nextjs-app
cd my-nextjs-app
npm run dev
Boom! Your Next.js app is running on http://localhost:3000
Project Structure
my-nextjs-app/
├── app/ # 🆕 App Router (Next.js 13+)
│ ├── layout.tsx # Global layout
│ ├── page.tsx # Homepage
│ ├── about/
│ │ └── page.tsx # Route /about
│ └── blog/
│ ├── page.tsx # Route /blog
│ └── [id]/
│ └── page.tsx # Dynamic route /blog/123
├── public/ # Static files
├── components/ # Your components
└── next.config.js # Next.js configuration
Next.js Superpowers
1. App Router - Modern Routing
// app/page.tsx - Homepage
export default function HomePage() {
return <h1>Home</h1>
}
// app/about/page.tsx - Page /about
export default function AboutPage() {
return <h1>About</h1>
}
// app/blog/[id]/page.tsx - Dynamic route
export default function BlogPost({ params }) {
return <h1>Article {params.id}</h1>
}
// app/layout.tsx - Global layout
export default function RootLayout({ children }) {
return (
<html>
<body>
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
</nav>
{children}
</body>
</html>
)
}
2. Server Components - Insane Performance
// ✅ Server Component - runs on the server
async function ProductsList() {
// This request is done server-side!
const products = await fetch('https://api.example.com/products')
return (
<div>
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
)
}
// ✅ Client Component - for interactivity
'use client'
import { useState } from 'react'
function ProductCard({ product }) {
const [liked, setLiked] = useState(false)
return (
<div>
<h3>{product.name}</h3>
<button onClick={() => setLiked(!liked)}>
{liked ? '❤️' : '🤍'
</button>
</div>
)
}
3. Static Site Generation (SSG)
// app/blog/[id]/page.tsx
export default function BlogPost({ params }) {
return <h1>Article {params.id}</h1>
}
// Generates all pages statically at build time
export async function generateStaticParams() {
const posts = await fetch('https://api.example.com/posts')
return posts.map(post => ({
id: post.id.toString()
}))
}
4. Server Actions - Full-stack Without an API
// actions.ts
'use server'
export async function createPost(formData) {
const title = formData.get('title')
const content = formData.get('content')
// Save directly to the database!
await db.posts.create({ title, content })
redirect('/blog')
}
// components/CreatePost.tsx
import { createPost } from './actions'
export default function CreatePost() {
return (
<form action={createPost}>
<input name="title" placeholder="Title" />
<textarea name="content" placeholder="Content" />
<button type="submit">Publish</button>
</form>
)
}
5. Automatic Optimizations
import Image from 'next/image'
import Link from 'next/link'
export default function HomePage() {
return (
<div>
{/* Automatically optimized image */}
<Image
src="/hero.jpg"
alt="Hero"
width={800}
height={400}
priority // Loads with priority
/>
{/* Automatic prefetching of links */}
<Link href="/about">About</Link>
{/* Automatic code splitting */}
<DynamicComponent />
</div>
)
}
Practical Examples
Blog with SSG
// app/blog/page.tsx - List of articles
export default async function BlogPage() {
const posts = await fetch('https://api.example.com/posts')
return (
<div>
<h1>My Blog</h1>
{posts.map(post => (
<article key={post.id}>
<h2>
<Link href={`/blog/${post.id}`}>
{post.title}
</Link>
</h2>
<p>{post.excerpt}</p>
</article>
))}
</div>
)
}
// app/blog/[id]/page.tsx - Individual article
export default async function BlogPost({ params }) {
const post = await fetch(`https://api.example.com/posts/${params.id}`)
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
)
}
// Static generation of all articles
export async function generateStaticParams() {
const posts = await fetch('https://api.example.com/posts')
return posts.map(post => ({ id: post.id.toString() }))
}
E-commerce with Server Actions
// app/products/[id]/page.tsx
import { addToCart } from './actions'
export default async function ProductPage({ params }) {
const product = await fetch(`/api/products/${params.id}`)
return (
<div>
<h1>{product.name}</h1>
<p>Price: {product.price}€</p>
<form action={addToCart}>
<input type="hidden" name="productId" value={product.id} />
<input type="number" name="quantity" defaultValue={1} />
<button type="submit">Add to cart</button>
</form>
</div>
)
}
// actions.ts
'use server'
import { cookies } from 'next/headers'
export async function addToCart(formData) {
const productId = formData.get('productId')
const quantity = formData.get('quantity')
// Retrieve the cart from cookies
const cart = cookies().get('cart')?.value || '[]'
const cartItems = JSON.parse(cart)
// Add the product
cartItems.push({ productId, quantity: parseInt(quantity) })
// Save to cookies
cookies().set('cart', JSON.stringify(cartItems))
redirect('/cart')
}
Advanced Configuration
next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
// Image optimizations
images: {
domains: ['example.com', 'cdn.example.com'],
formats: ['image/webp', 'image/avif'],
},
// Environment variables
env: {
CUSTOM_KEY: process.env.CUSTOM_KEY,
},
// Redirects
async redirects() {
return [
{
source: '/old-page',
destination: '/new-page',
permanent: true,
},
]
},
// Security headers
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'X-Frame-Options',
value: 'DENY',
},
],
},
]
},
}
module.exports = nextConfig
Middleware for Auth
// middleware.ts
import { NextResponse } from 'next/server'
export function middleware(request) {
// Checks auth for protected pages
if (request.nextUrl.pathname.startsWith('/dashboard')) {
const token = request.cookies.get('auth-token')
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
}
}
export const config = {
matcher: '/dashboard/:path*',
}
Alternatives to Next.js
🚀 Astro - The Minimalist
// Perfect for sites with little interactivity
---
const posts = await fetch('https://api.example.com/posts').then(r => r.json())
---
<html>
<head>
<title>My Astro site</title>
</head>
<body>
<h1>Blog</h1>
{posts.map(post => (
<article>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</body>
</html>
🎵 Remix - The Full-Stack
// Remix focuses on Web Standards
export async function loader({ params }) {
return json(await getPost(params.id))
}
export async function action({ request }) {
const formData = await request.formData()
await createPost(formData)
return redirect('/posts')
}
export default function Post() {
const post = useLoaderData()
return (
<div>
<h1>{post.title}</h1>
<Form method="post">
<input name="comment" />
<button type="submit">Comment</button>
</Form>
</div>
)
}
⚡ Vite + React Router - DIY
// If you want to control everything yourself
import { BrowserRouter, Routes, Route } from 'react-router-dom'
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/blog/:id" element={<BlogPost />} />
</Routes>
</BrowserRouter>
)
}
Deployment
Vercel (Creators of Next.js)
npm i -g vercel
vercel --prod
And there you go! Your app is online with HTTPS, CDN, edge functions...
Alternatives
- Netlify: Simple and effective
- Railway: Full-stack with database
- AWS Amplify: Complete AWS ecosystem
- Self-hosted: Docker + your server
Resources to Go Further
- 📚 Next.js Documentation
- 🎓 Next.js Learn Course
- 🎥 Next.js in 100 seconds
- 📖 Next.js Handbook
- 🆚 Next.js vs Remix vs Astro
SEO:
- Title: React : Next.js et les Meta-Frameworks | Formation Frameworks JS
- Description: Passez au niveau supérieur avec Next.js et les meta-frameworks. Apprenez le routing, le Server-Side Rendering (SSR), le Static Site Generation (SSG), les Server Actions et les optimisations automatiques.
- H1: React : Next.js et les Meta-Frameworks
- Canonical: /course/frameworks-javascript/formation-complete-react/nextjs-meta-frameworks