Published on

Next.js vs React.js

Authors
  • avatar
    Name
    Alessandro Battiato
    Twitter

In the world of front-end development, it’s easy to feel overwhelmed—especially if you’re just starting out. I remember when I was first learning HTML, CSS, and JavaScript, I felt like I had already accomplished a lot and thought it might be enough to break into the field as a junior front-end developer!

But as you’ll soon discover, coding with plain JavaScript isn’t all that common nowadays. Just take a look at a random job posting—you’ll see frameworks and libraries like Vue.js, Angular.js, React.js, and even meta-frameworks like Next.js listed as requirements. I know how intimidating this can feel and at times I thought it was too much for me. But I’m glad I didn’t give up! Today, I’m here to help you on your journey, and I hope you won’t change your mind if you’re pursuing a career in this field. (And if you’re already a working developer, you might still find some useful insights in this article!)

Imperative programming vs Declarative programming!

Before diving in, we need to talk about an important concept shared among many frameworks, which is Declarative programming, an approach used by React, Vue.js, and Angular.js.

Declarative programming focuses on what the outcome should be, without explicitly stating how to get there. React embodies this approach by allowing you to describe the UI in terms of its current state. For example, adding an item to a list in React might look like this:

const items = ['Item 1', 'Item 2', 'New Item']
return (
  <ul>
    {items.map((item) => (
      <li key={item}>{item}</li>
    ))}
  </ul>
)

In contrast, Imperative programming, typical of plain JavaScript, requires you to provide detailed instructions on how to achieve a result. For example, adding an item to a list in the DOM might look like this:

const list = document.getElementById('myList')
const listItem = document.createElement('li')
listItem.textContent = 'New Item'
list.appendChild(listItem)

The declarative approach is preferred because it abstracts away the complexity of DOM manipulation, allowing developers to focus on the logic and state of the application, making the code easier to maintain and reason about.

React.js, virtual DOM and Components

React.js is a JavaScript library primarily used for building user interfaces through a declarative, component-based approach. One of its key features is the Virtual DOM, an abstraction of the real DOM that allows React to update the User Interface efficiently. When a component's state changes, React's reconciliation algorithm compares the new Virtual DOM with the previous one and calculates the minimal number of updates needed. This minimizes interactions with the real DOM, which can be slow, resulting in improved performance.

React's component-based architecture allows developers to break down complex UIs into reusable, modular pieces. Think of it like building a page out of smaller LEGO blocks!

However, React also has its limitations when it comes to SEO (Search Engine Optimization). Since React primarily handles CSR (Client-side Rendering), search engines can struggle to index content, which can be a significant drawback for websites that rely on SEO for visibility.

In business, SEO is crucial for driving traffic. So, imagine creating a website for your company using React without addressing SEO—getting clients to your site could be tough. That’s where Next.js comes in and why it's an essential tool to qualify for many job opportunities!

Next.js, SEO and Core Web Vitals

Next.js builds on top of React, solving many of its limitations, especially around performance and SEO. While React excels in building dynamic user interfaces, Next.js goes further by enabling both SSR (Server-Side Rendering) and SSG (Static Site Generation).

But what do CSR, SSR, and SSG actually mean?

To begin with, the "client" is the user interface (UI), everything you're seeing right now on this post is part of the UI.

During CSR, the application loads and generates the output dynamically on the browser and the latter renders the pages using JavaScript, in other words, the components you wrote to build your UI are dynamically generated on the browser.

Instead, with SSR, the page is pre-rendered on the server, meaning the HTML is generated in advance and sent to the browser. This is faster than CSR because the page arrives fully formed, making the initial load much quicker. After the page is delivered, a process called hydration occurs, where the static HTML is enhanced with JavaScript to add interactivity—essentially "giving life" to the app. This allows the page to behave like a single-page application (SPA), where interactions don’t require reloading the entire page.

Let’s break this down by looking at a simple example of SSR in Next.js 13+:

// app/page.js (in the new App Directory structure)

export default async function HomePage() {
  const res = await fetch('https://api.example.com/data', { cache: 'no-store' })
  const data = await res.json()

  return (
    <div>
      <h1>Server-Side Rendered Data</h1>
      <ul>
        {data.map((item) => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  )
}

In this code snippet, you can see that the data is fetched during the rendering phase on the server, and the resulting HTML is sent to the client, improving both SEO and performance.

But SEO isn’t the only benefit. Next.js is also built with Core Web Vitals in mind. These are key metrics, defined by Google, that measure user experience on the web. Specifically, they include:

  • SSR and SSG ensure that pages are rendered faster and delivered more quickly to the user, improving LCP.

  • Automatic Image Optimization compresses and loads images efficiently, which speeds up page loading and improves both LCP and FID.

  • Code Splitting and Lazy Loading make sure that only the necessary parts of your JavaScript are loaded, reducing the time it takes for the page to become interactive, positively impacting FID.

  • Prefetching and Prerendering ensure that resources are ready when needed, minimizing delays in interactivity.

  • Stable Layouts are guaranteed by Next.js’ automatic handling of styles, reducing unexpected layout shifts and improving CLS.

Next.js not only improves SEO and performance but also helps meet Google’s Core Web Vitals standards. This is critical for businesses relying on visibility and user experience, which is why Next.js is a sought-after skill for front-end developers!

Final verdict - Who is the winner?

While Next.js offers many improvements, such as file-based routing and SEO optimization, it doesn’t always mean you should choose it over React.

There are still use cases where React alone is a great fit:

  • Dynamic SPAs: If your app is highly interactive and doesn’t rely heavily on SEO or SSR (for example, internal tools or dashboards), React’s lightweight setup without the overhead of Next.js can be more efficient.

  • PWA Development: For mobile-first web apps, React combined with tools like Create React App or Vite offers a streamlined, highly optimized setup without the need for SSR or SSG.

While there is no real "winner" among React and Next, the latter is not strictly mandatory for each project you will develop.

In fact, React alone is more than enough to build projects where SEO isn't a primary concern, such as Admin Dashboards for which i'd also suggest using React Admin which I widely used for internal projects where clients weren't directly involved (thus why SEO isn't necessary as there are no goods involved to be sold and visibility isn't a concern) and although Next.js could still be useful for routing, you can perfectly use React along with React Router and it will be more than enough to handle the issue!

I hope you found this article useful, see you soon! :)