Navigating the Basics of Next.js: A Beginner's Journey

Tags:#Programming#Front End Frameworks#NextJs#Side Projects

Description

What I've learned so far about Next.js through building my own website using React and Next.js

As primarily a backend engineer, diving into the realm of React and Next.js can feel both exhilarating and overwhelming. With the promise of efficient rendering, server-side rendering, and simplified routing, Next.js stands as a beacon of hope for developers seeking to streamline their web development process - myself included. Through the lens of building this website, I've encountered the fundamental principles of Next.js, and amidst the maze of concepts, one particular puzzle piece stood out: understanding the distinction between 'use-server' and 'use-client'.

Embracing the Basics of Next.js

Before delving into the intricacies of server-side versus client-side rendering, let's recap the basics of Next.js. At its core, Next.js is a React framework that aims to simplify the creation of React applications. It provides several key features out of the box, including:

  1. File-based Routing : Next.js embraces a simple and intuitive routing system based on the file structure of your project. Each React component represents a route, making navigation straightforward and predictable.
  2. Server-side Rendering (SSR) : One of the defining features of Next.js is its ability to render React components on the server side. This means that pages can be pre-rendered before being sent to the client, resulting in faster initial page loads and improved SEO performance.
  3. Static Site Generation (SSG) : In addition to SSR, Next.js supports static site generation, where pages are pre-built at build time and served as static HTML files. This approach further enhances performance by eliminating the need for server-side rendering on each request.

Unraveling the Mystery of 'use-server' vs 'use-client'

Now, let's address the elephant in the room: the perplexing disparity between 'use-server' and 'use-client' in the context of Next.js. To unravel this mystery, we need to understand how Next.js handles rendering.

When a user navigates to a page in a Next.js application, the rendering behavior can vary depending on the situation:

  • Server-side Rendering (SSR): In SSR, the page is rendered on the server for each request. This means that every time a user visits a page, the server generates the HTML content and sends it to the client.

  • Client-side Rendering (CSR): Conversely, in CSR, the initial HTML content sent to the client is minimal, often just a shell of the page. The client then takes over and renders the page dynamically using JavaScript.

Now, where do 'use-server' and 'use-client' come into play?

  • use-server: This term refers to components or functionality that are specifically designed to be executed on the server side. For example, code within a 'getServerSideProps' or 'getInitialProps' function will only run on the server, making it ideal for fetching data that is sensitive or dynamic.

  • use-client: Conversely, 'use-client' denotes components or logic intended for execution on the client side. This includes code within 'useEffect' hooks or event handlers that should only be triggered in the browser environment.

Incorporating Real-world Example

Let's consider my frustrating real-world scenario to illustrate the difference between 'use-server' and 'use-client'. Suppose you have a button component in your Next.js application with an `onClick` handler that calls an API function:

import React from 'react';

const MyComponent = () => {

  const handleClick = async () => {

    // Call some external API

    const response = await fetch('https://www.example.com/api/data&key=dont-expose-me');

    const data = await response.json();

    console.log(data);

  };

  return (

    <button onClick={handleClick}>Fetch Data</button>

  );

};

export default MyComponent;

In this scenario, if the API function requires server-side processing & authentication, attempting to call it directly from the client-side may result in errors or unexpected behavior - you could force it but, from my experience your super secret key will be naked to the world ☹️. To ensure proper execution, we can leverage server-side functionality by creating a serverless function within the api directory of our Next.js app:

// app/api/routes.ts

export default async function handler(req, res) {

  // Call to external API

  const response = await fetch('https://www.example.com/api/data&key=dont-expose-me');

  const data = await response.json();

  res.status(200).json(data);

}

By placing the API function in a file within the api directory, we ensure that it executes on the server-side, where it can properly handle any server-side logic or authentication required before making the external API call.

Conclusion:

Read the docs and be creative with distilling a solution, there are many ways to think of a singular problem/task.