umma.dev

Next.js 13 Notes

Notes on Next.js new release to go back on.

Routing

The new file system is built on top of React Server components.

There is a new directory called app, it works alongiside the existing directory called pages.

Components within app are React Server Components.

app
  pages
    index.tsx
    exampleFolder
      index.tsx
      component.tsx

When you create an app directory, you will need a page.tsx file.

There are also some special files noted below.

page.tsx: file for route of UI and make path accessible

layout.tsx: shared across multiple pages, accepts another layout/page of its child + can be nested

loading.tsx: optional file for specific part of an app - automatically wraps a page/child
layout in `React Suspense Boundary`; shows the loading component immediately on first loading or between navigating sibling routes

error.tsx: optional file used to isloate errors in specific parts of the app to
show specific errors - similar to `loading.tsx`, also wrapped in `React Suspense Boundary`

template.tsx: optional file, like layout but for navigation

head.tsx: optional file for `<head>` tag for the given route

pages uses client-side routing

app uses server-centric routing; server components and data fetching on server

React Server Components

The following is taken from a blog post on the Next.js site.

With Server Components, we're laying the foundations to build complex interfaces
 while reducing the amount of JavaScript sent to the client, enabling faster initial page loads.

When a route is loaded, the Next.js and React runtime will be loaded, which is cacheable
and predictable in size. This runtime does not increase in size as your application grows. Further,
the runtime is asynchronously loaded, enabling your HTML
from the server to be progressively enhanced on the client.

Data Fetching

Essentially this is support for React’s recent Promises RFC.

// app/page.js
async function getData() {
  const res = await fetch('https://api.example.com/...');
  // The return value is *not* serialized
  // You can return Date, Map, Set, etc.
  return res.json();
}

// This is an async Server Component
export default async function Page() {
  const data = await getData();

  return <main>{/* ... */}</main>;
}

This is what updated fetch looks like. SSG, SSR and ISR (Incremental Static Regeneration) all available through one API.

// This request should be cached until manually invalidated.
// Similar to `getStaticProps`.
// `force-cache` is the default and can be omitted.
fetch(URL, { cache: 'force-cache' });

// This request should be refetched on every request.
// Similar to `getServerSideProps`.
fetch(URL, { cache: 'no-store' });

// This request should be cached with a lifetime of 10 seconds.
// Similar to `getStaticProps` with the `revalidate` option.
fetch(URL, { next: { revalidate: 10 } });

Images

To add images you need to include two things in your component, the next/image import and the image you wanted to import.

import Image from 'next/image'
import pictureName from './file-path/imageName.jpeg'

export default MyComponent() {
  <section>
    <Image src={pictureName} alt="alt text" />
  </section>
}

The example above is for local images and .jpg, .png and .webp are currently supported. Next.js will automatically determine the width and height of the imported image file.

If you want to use a remote image, you will need to specify the width and height.

Loaders

The following is taken from the documentation for my own reference.

The default loader for Next.js applications uses the built-in Image Optimization API,
which optimizes images from anywhere on the web, and then serves them directly from
the Next.js web server. If you would like to serve your images directly from a CDN or
 image server, you can write your own
loader function with a few lines of JavaScript.

You can define a loader per-image with the loader prop, or at the application level with
the loaderFile configuration.

Priority

The priority property to the image will be the largest contentful paint (LCP) element for each page.

The LCP element is usually the largest image/text visible within the viewport of the page.

<Image
  src="example.jpeg"
  alt="example"
  width={100}
  height={100}
  priority
/>

Sizing

You can change the sizes of images in three ways:

  • Automatically using static import
  • Using height and width property on <Image/>
  • Using fill, which causes iamges to expand to fill its parent element

Fonts

This is a brand new font system, which optimises fonts including custom fonts. Also enables you to use Google fonts in an efficient way.

npm install @next/font

import { Inter } from '@next/font/google';

const inter = Inter();

<html className={inter.className}>

Custom fonts:

import localFont from '@next/font/local';

const myFont = localFont({ src: './my-font.woff2' });

<p className={myFont.className}>text</p>

Link

next/link will no longer require adding an <a> tag.

import Link from 'next/link'

// old
<Link href="/link-example">
  <a>Link</a>
</Link>

<Link href="/link-example">
  Link
</Link>