Next.js fundamentals
Tags: webdev, javascript
Published: 2023-04-21 09:56:49

## _Server-side rendering (SSR)_
Next.js allows you to perform server-side rendering of your React components,which means that your pages are pre-rendered on the server and delivered as static HTML to the client.The HTML page is generated on the server for each request.
React 18 and Next 12 introduce React server Components, Server completely rendered on the server and do not require client-side rendering.it can  degrade performance if it is heavy.

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

  return {
    props: {
      post
    }
  }
}

function Post({ post }) {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </div>
  )
}

export default Post

```

## Static site generation (SSG)
Static Generation describes the process of compiling and rendering a website at build time.The output is a bunch of static files, including the HTML file itself and assets like JavaScript and CSS.
With Static Generation, tools like Next.js try to render that page mostly like it would in the browser but at compile time. This gives us the ability to serve the entire content on first load.
If you only use _**getStaticProps **_ to fetch data, Next.js will fetch that data at build time, leaving you with a completely static page.
_**How to build a Next.js app
**_
Now that we have our application available, let’s try to build it.
npm run build


```
import path from "path";
import fs from "fs/promises";
import { Fragment } from "react";
import { useRouter } from "next/router";
function ProductDetailPage(props: any) {
  const router = useRouter();
  const { loadedProduct } = props;
  if (router?.isFallback) {
    return <h2> page Not Found!</h2>;
  }
  return (
    <Fragment>
      <h1>this is page</h1>
      <h1>{loadedProduct?.title}</h1>
      <h1>{loadedProduct?.description}</h1>
    </Fragment>
  );
}

async function getData() {
  const filePath = path.join(process.cwd(), "data", "dummy-data.json");
  const jsonData = await fs.readFile(filePath, "utf-8");
  const data = JSON.parse(jsonData);
  return data;
}

export async function getStaticProps(context: any) {
  const { params } = context;
  const productId = params.pid;
  const data = await getData();
  const product = data.products.find(
    (product: any) => product.id === productId
  );
  if (product) {
    return {
      props: {
        loadedProduct: product || null,
      },
    };
  }
}

export async function getStaticPaths() {
  const data = await getData();
  const ids = data.products.map((product: any) => product.id);
  const params = ids.map((id: string) => ({ params: { pid: id } }));
  return {
    paths: params,
    fallback: false,
  };
}

export default ProductDetailPage;


```

## Automatic code splitting
 Next.js splits your JavaScript into separate chunks for each route. When users load your application, Next.js only sends the code needed for the initial route.
Next.js automatically performs code splitting by analyzing the application code and determining which parts of it are needed for each page. It then generates separate chunks of JavaScript for each page, so that each page only loads the code it needs.

Overall, automatic code splitting is a powerful tool for optimizing the performance of a Next.js application, by reducing the initial load time and memory footprint of each page.

```
// pages/index.js

export default function Home() {
  return (
    <div>
      <h1>Welcome to my Next.js app!</h1>
      <p>This is a simple example of a Next.js application.</p>
    </div>
  )
}

```
Next.js provides a file-based routing system, which means that each file in the pages directory corresponds to a URL route in the application. For example, the index.js file corresponds to the root URL of the application (i.e. /).
Here's an example of using an API route in Next.js:

```
// pages/api/hello.js

export default function handler(req, res) {
  res.status(200).json({ message: 'Hello from the API!' })
}

```

## _Dynamic routing_
Next.js supports dynamic routing, which allows you to create routes with parameters that can be accessed by pages and components.

```
// pages/posts/[id].js

import { useRouter } from 'next/router'

export default function Post() {
  const router = useRouter()
  const { id } = router.query

  return (
    <div>
      <h1>Post {id}</h1>
      <p>This is the post with ID {id}</p>
    </div>
  )
}

```
we have a dynamic route for blog posts. The route is defined in a file called [id].js inside the pages/posts directory. The brackets around id indicate that this part of the URL is dynamic, and can be replaced with any value.
When a user navigates to a URL that matches this route, Next.js will automatically route the request to this page and pass the value of id as a query parameter. We use the useRouter hook from Next.js to get access to the router object, and then we extract the id query parameter from the query object.
Dynamic routing is a powerful feature of Next.js that allows you to build flexible and dynamic web applications.

## _Layouts_
Next.js provides a way to define reusable layouts that can be used across multiple pages. This can help you avoid duplicating code and improve maintainability.

```
// components/Layout.js

import Head from 'next/head'

const Layout = ({ children }) => {
  return (
    <div>
      <Head>
        <title>My Next.js App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <header>
        <nav>
          {/* navigation links */}
        </nav>
      </header>
      <main>
        {children}
      </main>
      <footer>
        {/* footer content */}
      </footer>
    </div>
  )
}

export default Layout

```
we define a Layout component that wraps around the content of each page. The component includes a header, navigation links, main content, and a footer. We also include a Head component from Next.js that sets the page title and favicon.

```
// pages/index.js

import Layout from '../components/Layout'

export default function Home() {
  return (
    <Layout>
      <h1>Welcome to my Next.js app!</h1>
      <p>This is a simple example of a Next.js application.</p>
    </Layout>
  )
}

```
we import the Layout component and wrap our page content (a heading and a paragraph) inside it. This ensures that the header, navigation, main content, and footer are consistent across all pages of the application.

## _API routes_
API routes in Next.js provide a simple and easy way to create serverless functions that can handle API requests. Here's an example of how you can create an API route in Next.js.


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

```
we have created an API route that responds with a JSON object containing a message. The route is defined in a file called hello.js inside the pages/api.
When a user makes a GET request to /api/hello, Next.js will automatically route the request to this page and invoke the handler function. The handler function takes two arguments: req (the incoming HTTP request) and res (the server response).