Next.js Continued

Next.js Continued

by Kenny Porterfield | Mon, May 24 2021

Category: JavaScript

Next & Vercel

In my last blog post on Next.js, we covered what Next.js is, talked about some of the benefits it provides, started a project and covered how to handle routing in Next.js. We'll cover some more essential aspects of Next.js today. To get started, we'll cover a couple more built-in React components in Next.js: Image & Head.

 

Image Component

Next.js can serve static assets, like images, from the top-level public directory. You can reference files inside the public directory from the root of the application similar to pages. For example, if you wanted to add a picture of a turtle to your site, you would add an images folder under public, and add turtle.jpg to that folder. The standard way to access this image using HTML would be:

 

<img src="/images/turtle.jpg" alt="Turtle" />

This way, your image could show up on the page but you would have to handle things like optimizing it and making it responsive on your own. Using Next.js's built-in Image Component can automatically resize and optimize images for you. It also avoids shipping large images to devices with a smaller viewport, and ensures the images only load when they enter the viewport, improving site performance. This automatic image optimization works wtih any image source, and Next.js can automatically adopt future image formats and serve them to browsers that support those formats.

 

To use the Image Component, you first have to import the component similar to how we imported the link component, then you can use the Image component inside of your other components and pass props to it to define how the image should look and behave.

 

<Image
    src="/images/turtle.jpg" // Route of the image file
    height={300} // Desired size with correct aspect ratio
    width={300} // Desired size with correct aspect ratio
    alt="Turtle"
/>

 

To view all the props you could pass to the image, you can check out Next's documentation on next/image.

 

Head Component

Next.js provides an easy way to access the head tag If you want to modify the metadata of a page for SEO purposes. This is by using the Head Component. First, you import Head from 'next/head' just like we did for Link and Image. Then, you can reference the Head Component. Any elements you put inside the Head Component will be appended to the head of the page. On our page we've been working with, we're talking about turtles. So let's say we want to customize the head for the page to show a relevant title tag. You would access the Head component, put the title tag in there, and it would be appended to that page when it is rendered.

 

import Link from 'next/link'
import Image from 'next/image'
import Head from 'next/head'

export default function FirstPost() {
  return (
    <>
      <Head>
        <title>Turtles</title>
      </Head>
      <h1>My favorite animals are turtles</h1>
      <Image
        src="/images/turtle.jpg" // Route of the image file
        height={300} // Desired size with correct aspect ratio
        width={300} // Desired size with correct aspect ratio
        alt="Turtle"
      />
      <h2>
        <Link href="/">
          <a>Back to home</a>
        </Link>
      </h2>
    </>
  )
}

 

Now, if you go back and forth between our index page and favorite/animals page, you should see the title change. 

 

CSS

In Next.js you can use a variety of approaches with CSS. We will cover three: Styled JSX, Global CSS, and CSS Modules. Global CSS is applied globally (as the name implies), while Styled JSX and CSS Modules are scoped, which can help avoid conflicts. Next.js compiles CSS using PostCSS out of the box, which takes care of vendor prefixes and you can configure to your own liking by creating a top-level file called postcss.config.js.

 

Styled JSX

This allows you to write CSS directly inside of a react component inside the style jsx tags like so:

 

<style jsx>{`
  p {
    color: blue;
  }
  div {
    background: red;
  }
  @media (max-width: 600px) {
    div {
      background: blue;
    }
  }
`}</style>

 

Global CSS

Global CSS can be used by creating a CSS file anywhere in your project and importing it into the pages/_app.js file. Any CSS you write in your global CSS file will apply to all pages and components in your Next.js app. Due to the global nature of stylesheets, to avoid conflicts you can only import them inside of this file, nowhere else.

 

CSS Modules

Next.js has built-in support for CSS Modules by using the [name].module.css file naming convention. You simply create a file with this naming convention and import that file wherever you want to use it. CSS Modules locally scope CSS by automatically generating a unique class name. This allows you to use the same CSS class name in different files without worrying about collisions, making them the ideal way to include component-level CSS. 

 

Static Pre-Rendering

Static pre-rendering is probably the biggest single benefit of Next.js. What pre-rendering means is that Next.js generates HTML for each page in advance, instead of having it all done by client-side JavaScript. This can result in better performance and better search engine optimization (SEO). Each generated HTML is associated with the minimal JS code necessary for that page. When a page is loaded by the browser, its JavaScript code runs and makes the page fully interactive, a process called hydration.

 

This means your app can be rendered without JavaScript. You can verify this by disabling the JavaScript in your browser and accessing the page. You should see that your app is rendered, because Next.js has pre-rendered the app into static HTML, allowing it to run without running JavaScript. By contrast, in a plain React.js app, there is no pre-rendering, so you won't be able to see the app if you disable JavaScript. Next.js pre-rendering improves our performance, SEO, and allows us to see our app without running JavaScript all out of the box.

 

Static Generation vs Server-Side Rendering

Next.js has two forms of pre-rendering: Static Generation and Server-Side Rendering. Next.js lets your choose which pre-rendering form to use for each page, so you can create a hybrid Next.js app using Static Generation for most pages and Server-Side Rendering for others.

 

Static Generation

Static Generation generates the HTML at build time, then the pre-rendered HTML is reused on each request. This form is recommended whenever possible because your page can be built once and served by CDN, which makes it much faster than having a server render the page on every request.

 

Server-Side Rendering

Server-side Rendering generates the HTML on each request. This can be useful because in some cases Static Generation is not a good idea if you cannot pre-render a page ahead of a user's request. This may be because your page shows frequently updated data, and the page content changes on every request. Server-Side Rendering will be slower, but the pre-rendered page will always be up-to-date.

 

First, we'll focus on Static Generation.

 

Static Generation with Data

For some pages, you might not be able to render the HTML without first fetching some external data. You may need to access the file system, fetch external API, or query your database at build time. Next.js supports this case — Static Generation with data — out of the box. In Next.js, when you export a page component, you can also export an asynchronous function called getStaticPropsgetStaticProps runs at build time in production, and inside the function, you can fetch external data and send it as props to the page.

 

Note: You can’t export it from non-page files. One of the reasons for this restriction is that React needs to have all the required data before the page is rendered.

 

export default function Home(props) { ... }

export async function getStaticProps() {
  // Get external data from the file system, API, DB, etc.
  const data = ...

  // The value of the `props` key will be
  //  passed to the `Home` component
  return {
    props: ...
  }
}

 

Essentially getStaticProps tells Next.js: "This page has some data dependencies, so when you pre-render this page at build time, make sure to resolve them first!"

 

You can fetch data from the file system (there are libraries that exist that make this easy), or an external API endpoint, or by querying a database directly. getStaticProps runs only on the server-side. It will never run on the client-side. It won’t even be included in the JS bundle for the browser. That means you can write code such as direct database queries without them being sent to browsers.

 

In development (npm run dev), getStaticProps runs on every request. In production, getStaticProps runs at build time. Because it’s meant to be run at build time, you won’t be able to use data that’s only available during request time, such as query parameters or HTTP headers.

 

If you have a need to fetch data at request time instead of at build time, you can try Server-side Rendering. To use Server-Side Rendering, you export getServerSideProps instead of getStaticProps from your page. Here's the starter code for getServerSideProps.

 

export async function getServerSideProps(context) {
  return {
    props: {
      // props for your component
    }
  }
}

 

Because getServerSideProps is called at request time, its parameter (context) contains request specific parameters.

 

You should use getServerSideProps only if you need to pre-render a page whose data must be fetched at request time. Time to first byte (TTFB) will be slower than getStaticProps because the server must compute the result on every request, and the result cannot be cached by a CDN without extra configuration.

 

If you do not need to pre-render the data, you can also use Client-side Rendering. This statically generates parts of the page that do not require external data. When the page loads, you can fetch external data from the client using JavaScript and populate the remaining parts. A good use-case for this is user dashboard pages. Because a dashboard is a private, user-specific page, SEO is not relevant, and the page doesn’t need to be pre-rendered. The data is frequently updated, which requires request-time data fetching.

 

SWR

The team behind Next.js has created a React hook for data fetching called SWR. It's great for fetching data on the client side. It handles caching, revalidation, focus tracking, refetching on interval, and more. Here’s an example usage:

 

import useSWR from 'swr'

function Profile() {
  const { data, error } = useSWR('/api/user', fetch)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}
 

You can get in-depth information about getStaticProps and getServerSideProps in the Next.js Data Fetching documentation.

 

Next Time

Next time we'll go over Dynamic Routing, make use of getStaticProps and some other functions, add some pages to our site, and see how easy it is to deploy it using Vercel.



Check out other JavaScript blogs.

Comments

Login or create an account to leave a comment.

Recent Blog Posts

Get in touch

Kenny Porterfield
kjport3@gmail.com
LinkedIn

Or, send me a message from here: