Next.js Trash Course - Part 3/3 
Tags: nextjs, react, javascript, webdev
Published: 2021-02-28 17:20:59

Hi again, devs.

Are you having a nice weekend there? I really hope so. 🙏

I should have released this final part yesterday, and my apologies for being late, but finally and after almost 3 months of coldness and darkness we have had few hours of sun shinning here so I decided to enjoy it. ☀️

If you are new here and have no idea what **Trash Course** means, please check 👇:
**HINT:** I am not ditching `Next.js` or anything.
- [Next.js Trash Course - Part 1/3](https://dev.to/vinicius77/next-js-trash-course-part-1-3-2dlb)
- [Next.js Trash Course - Part 2/3](https://dev.to/vinicius77/next-js-trash-course-part-2-3-3115)

But if you have been following along until here, please receive all my thankfulness. 🏆 So glad in having you aboard.

### What will be covered in this part 3/3? 🤩
- Static Assets, Custom Page Title and Metadata
- Fetching Data
- Dynamic Routes

### Part 9 - Static assets, custom page title and metadata 📕

We are likely use to static assets (e.g. favicons, images etc.) in web applications. In `Next.js` we can achieve it by placing them in the `public` folder.
 
I grab from the internet an _Ash Ketchum_ image just to use as an example and placed it on the public folder (`public/ash.png`). We will use it as our logo in the `Navbar` component.

```jsx
import Link from 'next/link';
import Image from 'next/image'; // we import it and use below as following

export const Navbar = () => {
  return (
    <nav>
      <div className="brand">
        {/** Here 👇 */}
        <Image src="/ash.png" width={60} height={60} /> 
      </div>
      <Link href="/">Home</Link>
      <Link href="/about">About</Link>
      <Link href="/dev/">Dev</Link>
    </nav>
  );
};
```
We could also have used the classic `img` tag if we want to:  `<img src="/ash.png" alt="ash ket" />`.
 
Some points to consider when using the `Next.js Image` component are described below:

- We need to specify its `width` and `height` properties explicitly otherwise an error will be thrown.
- It automatically makes the image responsive based on the properties provided.
- It utilizes the _lazy loading_ design pattern. it is only loaded when it needs to be rendered, for example, if the image is placed in our footer, `Next.js` would only load it when scrolling down the page reaches the footer.

Talking about adding `metadata` and `customized title` to different pages it can be as simple as the following example in our `Home`:

```jsx
import Link from 'next/link';
import Head from 'next/head'; // We import the Next.js' Head component

export default function Home() {
  return (
    <>
      {/** 👇👇👇 */}
      <Head>
        {/** Add the title and metadata for the page as shown below*/}
        <title>Creep Home Page</title>
        <meta name="keywords" content="next,random design,trash course" />
      </Head>
      {/** 👆👆👆 */}
      <div className="container">
        <h1>Hello Next.js</h1>
        <div>
          <Link href="/about">About</Link>
        </div>
      </div>
    </>
  );
}
```

Remember to wrap all the components using only one parent element otherwise an error about having multiple parent elements will be thrown. I have used empty tags `<></>` but it could be a `React Fragment`, a `<div>` etc.

### Part 10 - Fetching Data ⬇️ 💽

Normally in an application the data we fetch comes from the server-side, for example, a database, a web server and so on.

In order to make it simple, let's fetch some mock data from [JSON API Placeholder](https://jsonplaceholder.typicode.com)

In a `React` application we would fetch data using the `useEffect` hook and the request would be made in the browser. 

In `Next.js` it differs a little bit because all the components are first pre-rendered by the time they reach the browser. In other words we need to fetch the data in advance so the rendered components will have already the data in their templates.

Here is where the `Next.js`' `getStaticProps` function comes to the stage. I will use our dev's homepage (`pages/dev/index.js`) to fetch data from `https://jsonplaceholder.typicode.com/users`.

In our `dev's index page` (`pages/dev/index.js`) we must create the `getStaticProps` function and `export` it.

```jsx
export const getStaticProps = async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/users');
  const data = await response.json();

  return { props: { users: data } };
};
```

⚠️ **DON'T** write any code inside of the `getStaticProps` function that you expect to run in the browser. ⚠️

- `getStaticProps` is a special `async function` because it runs at build time. Inside of this function we add our `fetch requests` in order to, guess what?, fetch any data we want to render in our component. 😉

The data we have fetched from the API endpoint is now attached to the props (`{ users }`) of our component:

```jsx
export default function Home({ users }) {
  return (
    <div>
      <h1>Hello Devs</h1>
      <ul>
        {users.map((user) => (
          <li key={user.id}>
            <p>{user.username}</p>
            <p>{user.email}</p>
          </li>
        ))}
      </ul>
      <Button>Dev Button</Button>
    </div>
  );
}
```

And that's it. Of course it is just a basic implementation but as a starting point it works pretty well. 

I also know I should add some styles to it but this article is becoming longer than I thought so see it as a _homework_ for you. 🤜 🤛

### Part 11 - Dynamic Routes 🛣️ 🛣️

It would be nice if from the users list we fetched data we could see more information about a specific user when clicking on it. There are some steps to be followed in order to achieve that but nothing complicated at all. 

We need to: ✏️
- Generate dynamic routes for each user, 
- Create a component to hold the user details.

Inside of `pages/dev` folder we will create a file called `[id].js` so we can have routes at `/dev/id` where the `id` is whatever user's id we pass to the component. 

The `[id]` syntax you saw before is a way to tell: _" - Hey `Next.js`, I will be passing some route parameters to this component so be aware of that."_.

Our `pages/dev/[id].js` component initially will look like the following:

```jsx
import React from 'react';

const UserInfo = () => {
  return <div>Boom!</div>;
};

export default UserInfo;
```
If now you go to the route `http://localhost:3000/dev/2` or whatever value you pass as a route parameter you should see `Boom!` rendered there. It is not dynamic yet so let´s make some changes to make it happen.

- Let's create a link in every user in the list so when we click on it we use its id as a parameter to fetch his / her individual data. (`dev/index.js`).

```jsx
import { Button } from '../../components/Button';
import Link from 'next/link';

export const getStaticProps = async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/users');
  const data = await response.json();

  return { props: { users: data } };
};

export default function Home({ users }) {
  return (
    <div>
      <h1>Hello Devs</h1>
      <ul>
        {users.map((user) => (
          {/** 👇👇👇 */}
          <Link href={`/dev/${user.id}`} key={user.id}>
            {/** LAZY styling 😅 🙈 */}
            <li style={{ cursor: 'pointer' }}>
              <p>{user.username}</p>
              <p>{user.email}</p>
            </li>
          </Link>
        ))}
      </ul>
      <Button>Dev Button</Button>
    </div>
  );
}
```
And finally we need to make a call to the endpoint using the `user's id` in order to fetch a user's individual info. (`pages/dev/[id].js`).

```jsx
export const getStaticPaths = async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/users');
  const data = await response.json();

  const userPaths = data.map((user) => {
    return { params: { id: user.id.toString() } };
  });

  return {
    paths: userPaths,
    fallback: false,
  };
};

export const getStaticProps = async (context) => {
  const userID = context.params.id;
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/users/${userID}`
  );
  const data = await response.json();

  return { props: { user: data } };
};

const UserInfo = ({ user }) => {
  return (
    <div>
      <h2>User Info</h2>
      <p>username: {user.username}</p>
      <p>email: {user.email}</p>
      <p>
        address: {user.address.street} - {user.address.city}
      </p>
      <p>phone: {user.phone}</p>
      <p>website: {user.website}</p>
    </div>
  );
};

export default UserInfo;
```
Don't be scary! Most of the content there we are already familiar with. The new concepts I am going to try to explain now.

- The `getStaticPaths` function: ✔️ 

```jsx
export const getStaticPaths = async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/users');
  const data = await response.json();

  const userPaths = data.map((user) => {
    return { params: { id: user.id.toString() } };
  });

  return {
    paths: userPaths,
    fallback: false,
  };
};
```
It is also a special function. It fetches the data and returns an array containing all the **static paths** of every single user as shown below. 
```jsx
//...
const userPaths = data.map((user) => {
  return { params: { id: user.id.toString() } };
});

return {
  paths: userPaths,
  fallback: false,
};
//...
```


Remember that all the pages are build at run time. Think that it returns an array like this: `[{ /dev/1 }, { /dev/2}, ... , { /dev/10 }]`. 
The `fallback: false` option, is out of scope for now, but if you remove it will throw an error.

- The `getStaticProps` function (same as before but slightly different): ✔️ 

```jsx
export const getStaticProps = async (context) => {
  const userID = context.params.id;
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/users/${userID}`
  );
  const data = await response.json();

  return { props: { user: data } };
};
```

It has now access to the `props` returned from the `getStaticPaths` function through the `context` object.
 
From this object it can access the id of each user, fetch their individual information and send it to the `UserInfo` component (`/pages/dev/[1].js`).

<hr />

And that's all, devs! I think we made it, guys! 🏅 🥇 🎉 🍾

![Carlton Dance](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i9z4gfou7a6fge3acsgz.gif)

<hr />

Indeed, there is a lot of stuff to be explored but my aim was just to make a quick introduction to `Next.js`.

I am planning to release an extra post introducing the `api` folder (`pages/api`) and also how to deploy our application on `Vercel` but it depends a lot of how my week goes so I cannot promise anything, unfortunately. 😓

I hope you guys have enjoyed our time together and also have learned something from it. 😃 If you have created your own version using the content of this series, please share with us. 

We would be glad to see the results of your hard work. 💪 💎

Thanks a ton and be safe everybody! 🙇‍♂️