Skip to main content

Next.js vs React

Introduction

If you're beginning your journey into modern web development, you've likely encountered both React and Next.js. While they're closely related, understanding their relationship and differences is crucial for making informed project decisions.

React is a JavaScript library for building user interfaces, primarily focusing on the view layer of applications. Next.js, on the other hand, is a framework built on top of React that provides additional structure, features, and optimizations.

In this tutorial, we'll explore the relationship between React and Next.js, their key differences, and scenarios where one might be preferable over the other.

Understanding React

What is React?

React is a declarative, component-based JavaScript library developed by Facebook (now Meta) for building user interfaces. It allows developers to create reusable UI components and efficiently update the DOM when data changes.

Key Features of React

  • Component-Based Architecture: Break down your interface into reusable components
  • Virtual DOM: Efficiently update only what needs to change
  • JSX: Write HTML-like syntax within JavaScript
  • One-way Data Flow: Data flows down from parent components to children

A Simple React Component Example

jsx
import React, { useState } from 'react';

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

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

export default Counter;

With React alone, you need to make decisions about:

  • Routing
  • Data fetching
  • Build configuration
  • Server-side rendering
  • Deployment

Understanding Next.js

What is Next.js?

Next.js is a React framework created by Vercel that provides structure, features, and optimizations for your React applications. It aims to solve common challenges in React development by providing built-in solutions.

Key Features of Next.js

  • File-based Routing: Define routes based on your file structure
  • Server-Side Rendering (SSR): Pre-render pages on the server
  • Static Site Generation (SSG): Generate static HTML at build time
  • API Routes: Build API endpoints within your Next.js app
  • Image Optimization: Automatic image optimization
  • Built-in CSS and Sass Support: Import CSS/Sass files directly
  • Zero Configuration: Works out of the box with sensible defaults

A Simple Next.js Page Example

jsx
// pages/index.js
import { useState } from 'react';

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

return (
<div>
<h1>Welcome to my Next.js app</h1>
<h2>Counter: {count}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}

Key Differences: React vs Next.js

1. Routing

React: Requires third-party libraries like React Router.

jsx
// React Router example
import { BrowserRouter, Routes, Route } from "react-router-dom";

function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</BrowserRouter>
);
}

Next.js: Provides file-based routing out of the box.

jsx
// In Next.js, simply create these files:
// pages/index.js -> Automatically becomes the / route
// pages/about.js -> Automatically becomes the /about route
// pages/contact.js -> Automatically becomes the /contact route

2. Rendering Methods

React: Client-side rendering by default. Server-side rendering requires additional setup.

Next.js: Offers multiple rendering options:

  • Server-Side Rendering (SSR):
jsx
// pages/ssr-page.js
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();

return {
props: { data } // Passed to the page component as props
};
}

export default function SSRPage({ data }) {
return <div>Server-rendered data: {data.title}</div>;
}
  • Static Site Generation (SSG):
jsx
// pages/ssg-page.js
export async function getStaticProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();

return {
props: { data },
revalidate: 60 // Re-generate page every 60 seconds (optional)
};
}

export default function SSGPage({ data }) {
return <div>Statically generated data: {data.title}</div>;
}
  • Client-Side Rendering: Works just like React

3. Data Fetching

React: Uses hooks like useEffect for data fetching in components.

jsx
import { useState, useEffect } from 'react';

function UserProfile() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);

useEffect(() => {
async function fetchUser() {
try {
const response = await fetch('https://api.example.com/user/1');
const data = await response.json();
setUser(data);
} catch (error) {
console.error('Error fetching user:', error);
} finally {
setLoading(false);
}
}

fetchUser();
}, []);

if (loading) return <div>Loading...</div>;
if (!user) return <div>User not found</div>;

return <div>Hello, {user.name}</div>;
}

Next.js: Provides specialized data fetching methods.

jsx
// pages/user/[id].js
export async function getServerSideProps({ params }) {
const res = await fetch(`https://api.example.com/user/${params.id}`);
const user = await res.json();

return { props: { user } };
}

export default function UserProfile({ user }) {
return <div>Hello, {user.name}</div>;
}

4. Build Process and Configuration

React: Requires setup with tools like Create React App, webpack, babel, etc.

Next.js: Zero configuration with sensible defaults, built-in TypeScript support, and automatic code splitting.

5. API Routes

React: Requires separate backend setup for API endpoints.

Next.js: Includes API routes functionality.

jsx
// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ message: 'Hello from the API!' });
}

When to Use React vs Next.js

Choose React When:

  • Building a single-page application (SPA) with minimal routes
  • Creating a widget or component to embed in existing applications
  • Working with a team that already has a routing and build solution
  • Integrating with an existing backend that handles most logic
  • Learning the fundamentals of component-based architecture

Choose Next.js When:

  • Building a complete web application with multiple pages
  • SEO is important for your project
  • You need fast page loads and better performance
  • You want built-in API routes alongside your frontend
  • You prefer convention over configuration
  • You need server-side rendering or static site generation

Real-World Application Comparison

Let's see how the same application would differ when implemented in React vs Next.js.

Blog Application Example

React Implementation

jsx
// App.js
import { useState, useEffect } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import HomePage from './pages/HomePage';
import BlogPost from './pages/BlogPost';
import NotFound from './pages/NotFound';

function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/blog/:id" element={<BlogPost />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}

// pages/BlogPost.js
import { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';

function BlogPost() {
const [post, setPost] = useState(null);
const [loading, setLoading] = useState(true);
const { id } = useParams();

useEffect(() => {
fetch(`https://api.example.com/posts/${id}`)
.then(res => res.json())
.then(data => {
setPost(data);
setLoading(false);
});
}, [id]);

if (loading) return <div>Loading...</div>;
if (!post) return <div>Post not found</div>;

return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}

Next.js Implementation

jsx
// pages/index.js
import Link from 'next/link';

export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();

return {
props: { posts },
revalidate: 60 // Regenerate page every 60 seconds
};
}

export default function HomePage({ posts }) {
return (
<div>
<h1>My Blog</h1>
<ul>
{posts.map(post => (
<li key={post.id}>
<Link href={`/blog/${post.id}`}>
{post.title}
</Link>
</li>
))}
</ul>
</div>
);
}

// pages/blog/[id].js
export async function getStaticPaths() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();

const paths = posts.map(post => ({
params: { id: post.id.toString() }
}));

return { paths, fallback: 'blocking' };
}

export async function getStaticProps({ params }) {
const res = await fetch(`https://api.example.com/posts/${params.id}`);
const post = await res.json();

return {
props: { post },
revalidate: 60
};
}

export default function BlogPost({ post }) {
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}

Summary

React is a library focused on building user interfaces with components. It provides the fundamental building blocks but leaves many architectural decisions to you. Next.js is a framework built on top of React that provides additional structure and features out of the box.

Key differences include:

FeatureReactNext.js
RoutingManual setup requiredFile-based routing
RenderingClient-side by defaultMultiple options (SSR, SSG, CSR)
Data FetchingManual in useEffectBuilt-in data fetching methods
API RoutesSeparate backend neededIntegrated API routes
Image OptimizationManual implementationBuilt-in component
Build ProcessManual configurationZero configuration

The choice between React and Next.js depends on your project requirements, team preferences, and the specific features you need. If you're just starting out, learning React fundamentals first will make it easier to understand Next.js concepts later.

Additional Resources

Exercises

  1. Create a simple counter application in both React and Next.js, and compare the code structure.
  2. Build a blog homepage that fetches posts from an API in both React and Next.js.
  3. Implement a product listing page with filtering in both technologies.
  4. Create a form with validation in React, then convert it to a Next.js application.
  5. Add an API endpoint in a Next.js application that returns the current time.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)