
React vs Next.js — What Actually Changes? A Beginner-Friendly Deep Dive
React is one of the most popular libraries for building modern web apps. If you’ve learned React, you’re already on the right track. But as your app grows, you may notice problems:
Next.js 15 addresses these issues by combining the best of React with powerful features like server-side rendering, built-in routing, and more. Let’s explore how React and Next.js 15 differ, step by step.
What Happens When You Visit a React App?
When a user visits a React app (e.g., built with create-react-app or Vite), here’s what happens:
Example: E-commerce Landing Page in React
Consider a landing page with a header, navigation, and a list of featured products fetched from an API:
import { useState, useEffect } from 'react'; import axios from 'axios'; function LandingPage() { const [products, setProducts] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { axios.get('/api/featured-products') .then((res) => { setProducts(res.data); setLoading(false); }); }, []); return ( <div> <header>Shop Now!</header> <nav>Home | Products | Cart</nav> <section> <h1>Welcome to Our Store</h1> {loading ? ( <p>Loading...</p> ) : ( <div> <h2>Featured Products</h2> <ul> {products.map(product => ( <li key={product.id}>{product.name}</li> ))} </ul> </div> )} </section> </div> ); }
Outcome:
Problems with Plain React (Client-Side Rendering)
How Next.js 15 Solves These Problems
Next.js 15 enhances React with features like server-side rendering (SSR), React Server Components, and the App Router. Here’s how it works:
Example: E-commerce Landing Page in Next.js 15
Using Next.js 15’s App Router and React Server Components, the same landing page is handled differently:
// app/page.tsx import { db } from "@/lib/db"; export default async function LandingPage() { const products = await db.getFeaturedProducts(); // Fetches on the server return ( <div> <header>Shop Now!</header> <nav>Home | Products | Cart</nav> <section> <h1>Welcome to Our Store</h1> <div> <h2>Featured Products</h2> <ul> {products.map(product => ( <li key={product.id}>{product.name} - ${product.price}</li> ))} </ul> </div> </section> </div> ); }
What Happens:
Adding Interactivity: For client-side interactivity (e.g., an “Add to Cart” button), use a client component:
// app/components/AddToCartButton.tsx 'use client'; import { useState } from 'react'; export function AddToCartButton({ productId }) { const [added, setAdded] = useState(false); return ( <button onClick={() => setAdded(!added)}> {added ? 'Added!' : 'Add to Cart'} </button> ); }
Integrate it into the server component:
// app/page.tsx (updated) import { db } from "@/lib/db"; import { AddToCartButton } from "@/components/AddToCartButton"; export default async function LandingPage() { const products = await db.getFeaturedProducts(); return ( <div> <header>Shop Now!</header> <nav>Home | Products | Cart</nav> <section> <h1>Welcome to Our Store</h1> <div> <h2>Featured Products</h2> <ul> {products.map(product => ( <li key={product.id}> {product.name} - ${product.price} <AddToCartButton productId={product.id} /> </li> ))} </ul> </div> </section> </div> ); }
Outcome:
Extra Features in Next.js 15
Summary: React vs Next.js 15
Feature | React | Next.js 15 |
---|---|---|
Initial HTML | Blank <div> | Fully rendered content |
SEO | Poor | Excellent |
First Load | Slow | Fast |
Data Fetching | Client-side only | Server-side by default |
Routing | Manual (React Router) | File-based |
Bundle Size | Large | Smaller (server components) |
API Support | Needs backend | Built-in |
Server Logic | Not available | Server Actions supported |
Final Thoughts
React is a powerful frontend library, but it requires manual handling of routing, SEO, and performance. Next.js 15 builds on React, offering:
If you know React, Next.js 15 is the logical next step to build fast, scalable, and SEO-friendly web apps.