DEV Community

Cover image for From React to Next.js — What Changed, What Got Better, and What I Built to Prove It
Kennang
Kennang

Posted on

From React to Next.js — What Changed, What Got Better, and What I Built to Prove It

When I first started my web development journey at rebasecodecamp, React was my entry point into the world of frontend development. It taught me components, state, props, hooks the fundamentals that every modern JS developer needs. But at some point, I hit a wall. Questions like “How do I handle SEO?”, “Why is my page loading so slow?”, and “How do I fetch data securely on the server?” started coming up constantly.
Then I discovered Next.js and it answered all of those questions in a beautifully opinionated way.
In this article, I’ll walk you through the core differences between React and Next.js, why Next.js has clear advantages for production apps, and a mini project where I tested Server-Side Rendering (SSR) — something React alone simply cannot do natively.

React vs Next.js — The Core Differences
Before we dive into code, let’s understand the fundamental difference in philosophy.
React is a UI library. It handles the view layer — how components render and update. Everything else (routing, data fetching strategy, SSR) is your responsibility to wire up.
Next.js is a full-stack React framework built on top of React. It makes opinionated decisions about routing, rendering, and optimization so you can focus on building features.
Here’s a quick comparison:
∙ Routing → React uses manual setup with React Router. Next.js uses automatic file-based routing.
∙ Rendering → React does Client-Side only (CSR). Next.js supports CSR, SSR, SSG, and ISR.
∙ SEO → React is poor by default. Next.js is excellent out of the box.
∙ API Routes → React has none. Next.js has them built in.
∙ Image Optimization → React requires manual work. Next.js has a built-in Image component.
∙ Code Splitting → React requires manual setup. Next.js does it automatically.
∙ Full-stack capability → React cannot. Next.js can.

Advantage 1 — File-Based Routing (No More React Router Headaches)
In React, you’d install react-router-dom and manually define every route:

// React — App.jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Blog from './pages/Blog';

function App() {
return (


} />
} />
} />


);
}

In Next.js (App Router), you just create files:

app/
├── page.jsx → /
├── about/
│ └── page.jsx → /about
└── blog/
└── [id]/
└── page.jsx → /blog/:id

// Next.js — app/blog/[id]/page.jsx
export default function BlogPost({ params }) {
return

Blog Post: {params.id}

;
}

Zero configuration. Zero extra packages. The file system is your router.

Advantage 2 — Server-Side Rendering and SEO
This is the biggest game-changer. React renders everything on the client — meaning search engines often see a blank page before JavaScript loads. Next.js renders pages on the server, sending fully populated HTML to the browser.
In React (CSR), the user sees a blank screen until JavaScript loads and fetches data:

// React — fetching data client-side
import { useState, useEffect } from 'react';

export default function Products() {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
fetch('/api/products')
.then(res => res.json())
.then(data => {
setProducts(data);
setLoading(false);
});
}, []);

if (loading) return

Loading...

;

return (

    {products.map(p =>
  • {p.name}
  • )}

);
}

Problems: empty HTML on first load, poor SEO, loading spinner experience for users.
In Next.js (SSR), the server fetches data and sends complete HTML — no loading state needed:

// Next.js — app/products/page.jsx (Server Component)
async function getProducts() {
const res = await fetch('https://api.example.com/products', {
cache: 'no-store'
});
return res.json();
}

export default async function Products() {
const products = await getProducts();

return (

    {products.map(p =>
  • {p.name}
  • )}

);
}

The HTML is pre-populated before it ever reaches the browser. Google can read it. Users see it instantly.

Advantage 3 — Built-in API Routes (Full-Stack in One Project)
With React, you need a separate backend for server-side logic. With Next.js, you write API endpoints in the same project:

// Next.js — app/api/hello/route.js
export async function GET(request) {
return Response.json({ message: 'Hello from the server!', timestamp: Date.now() });
}

export async function POST(request) {
const body = await request.json();
return Response.json({ success: true, received: body });
}

Your frontend and backend live together. Deployment is one command. No CORS headaches for internal APIs.

Advantage 4 — Image Optimization Out of the Box
React has no built-in image optimization. Next.js has a powerful Image component that automatically lazy loads images, resizes for different screen sizes, converts to modern formats like WebP and AVIF, and prevents layout shift.

// React — manual, unoptimized
Hero

// Next.js — automatically optimized
import Image from 'next/image';

src="/hero.jpg"
alt="Hero"
width={800}
height={400}
priority
/>

The Mini Project — News Feed with SSR
To prove the power of SSR, I built a News Feed App that fetches the latest tech articles from a public API and displays them. This is where Next.js does something React fundamentally cannot do natively.

// app/news/page.jsx

export const metadata = {
title: 'Latest Tech News | rebasecodecamp',
description: 'Real-time tech news powered by Next.js Server-Side Rendering',
};

async function fetchNews() {
const res = await fetch(
https://newsapi.org/v2/top-headlines?category=technology&pageSize=10&apiKey=${process.env.NEWS_API_KEY},
{ cache: 'no-store' }
);
if (!res.ok) throw new Error('Failed to fetch news');
return res.json();
}

export default async function NewsPage() {
const data = await fetchNews();
const articles = data.articles;

return (

Latest Tech News



Rendered on the server at: {new Date().toLocaleTimeString()}

  <div className="grid gap-6">
    {articles.map((article, index) => (
      <article key={index} className="border rounded-xl p-5 shadow-sm">
        <h2 className="text-xl font-semibold mb-2">{article.title}</h2>
        <p className="text-gray-600 mb-3">{article.description}</p>
        <div className="flex justify-between text-sm text-gray-400">
          <span>{article.source.name}</span>
          <span>{new Date(article.publishedAt).toLocaleDateString()}</span>
        </div>
        <a href={article.url} target="_blank" rel="noopener noreferrer"
           className="inline-block mt-3 text-blue-600 font-medium">
          Read Full Article →
        </a>
      </article>
    ))}
  </div>
</main>
Enter fullscreen mode Exit fullscreen mode

);
}

Why React can’t do this the same way:
Notice this line: apiKey=${process.env.NEWS_API_KEY}
In a React CSR app, any fetch in a component runs in the browser. That means your API key would be exposed in the network tab for anyone to inspect — a real security risk.
In Next.js Server Components, the fetch runs entirely on the server. The API key never touches the client. The browser only receives the final rendered HTML.
On top of that, because the page is rendered server-side, there is no loading spinner — content is there on first paint. The page is SEO-friendly because search engines index actual article titles, not a loading skeleton. And Time to First Contentful Paint is significantly faster.
Bonus — Incremental Static Regeneration (ISR)

// app/blog/[slug]/page.jsx

export async function generateStaticParams() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
return posts.map(post => ({ slug: post.slug }));
}

export default async function BlogPost({ params }) {
const post = await fetch(
https://api.example.com/posts/${params.slug},
{ next: { revalidate: 60 } }
).then(r => r.json());

return (

{post.title}


{post.content}



);
}

This is ISR — pages are generated at build time and automatically regenerated every 60 seconds in the background. React cannot do this without a separate backend and complex caching infrastructure.

When to Use What
Use React when you’re building a dashboard or internal app that doesn’t need SEO, when you already have a backend API and just need a UI layer, or when you want maximum flexibility in choosing your own tools.
Use Next.js when SEO matters — for blogs, e-commerce, or marketing sites. When you need server-side data fetching with secure API calls. When you want a full-stack solution in one framework. When performance and Core Web Vitals are priorities.

Final Thoughts
Learning React at rebasecodecamp gave me the foundation I needed — components, state, the React mental model. But Next.js took everything I knew and made it production-ready. SSR, file-based routing, API routes, image optimization — these aren’t nice-to-haves. In professional development, they’re expected.
If you’ve mastered React and haven’t tried Next.js yet, this is your sign. Start with the official Next.js docs and build something real.
And if you’re just getting started on your dev journey, rebasecodecamp is where mine began — and I’m grateful for every lesson.
Happy coding! Drop your questions in the comments — I read every one.

nextjs #react #javascript #webdev #rebasecodecamp #programming #frontend #ssr #webperformance

Top comments (0)