Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
February 28, 2021 05:20 pm GMT

Next.js Trash Course - Part 3/3

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.

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.

import Link from 'next/link';import Image from 'next/image'; // we import it and use below as followingexport 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>  );};
Enter fullscreen mode Exit fullscreen mode

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:

import Link from 'next/link';import Head from 'next/head'; // We import the Next.js' Head componentexport 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>    </>  );}
Enter fullscreen mode Exit fullscreen mode

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

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.

At the top of the file (pages/dev/index.js) we must import it.

export const getStaticProps = async () => {  const response = await fetch('https://jsonplaceholder.typicode.com/users');  const data = await response.json();  return { props: { users: data } };};
Enter fullscreen mode Exit fullscreen mode

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:

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>  );}
Enter fullscreen mode Exit fullscreen mode

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:

import React from 'react';const UserInfo = () => {  return <div>Boom!</div>;};export default UserInfo;
Enter fullscreen mode Exit fullscreen mode

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 lets 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).
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>  );}
Enter fullscreen mode Exit fullscreen mode

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).

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;
Enter fullscreen mode Exit fullscreen mode

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:
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,  };};
Enter fullscreen mode Exit fullscreen mode

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.

//...const userPaths = data.map((user) => {  return { params: { id: user.id.toString() } };});return {  paths: userPaths,  fallback: false,};//...
Enter fullscreen mode Exit fullscreen mode

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):
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 } };};
Enter fullscreen mode Exit fullscreen mode

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).

And that's all, devs! I think we made it, guys!

Carlton Dance

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!


Original Link: https://dev.to/vinicius77/next-js-trash-course-part-3-3-3igc

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To