Frontend developer focused on inclusive design

Next.js routing

Routing is a fundamental aspect of any application. In Next.js, App Router built on React Server Components. It support shared layouts, nested routing, loading states, error handling, and other useful things for web application.

Static routes

Routes are organized within the app directory. Each folder corresponds to a URL segment. For nested routes, place folders inside one another to reflect the desired URL structure.

In addition to organizing routes with folders, Next.js uses specific files in folders to handle different functionalities and render components.

Page.js

The page.js file in Next.js 13 App Route is used to define the unique UI for a specific route in application. This file is required to make a route segment available for public access.

Pages are server components by default but can be set as client components.

Use server components when possible because they are faster and ship less JavaScript to the client. For React Context Api, use client components.

Note, server components can be wrapped with client components, as shown in the Next.js and FluentUI example.

Pages can fetch data.

Fetching data in a server component can increase the page load time, meaning that the data may take time to load. Example of fetching data in page component:

// Define an asynchronous functional React component named 'page'
const page = async () => {
	// Fetch data from the specified API URL using the 'fetch' function and await the response
	const response = await fetch('api url goes here');

	// Parse the response as JSON and store it in the 'data' variable
	const data = await response.json();

	// Return a JSX block containing a 'div' that displays the fetched data as a string
	return (
		<div>{JSON.stringify(data)}</div>
	);
};

// Export the 'page' component as the default export from this module
export default page

The fetched data will be shown once it’s available.

How to check if an API request is currently loading?

Since it's a server-side component, it's not possible to use React hooks. React hooks rely on client-side APIs and can only be used in client-side components. Next.js provides a way to manage loading state in server components.

Loading.js

The loading.js file in Next.js 13 App Route is used to display an immediate loading state from the server while a route segment's content is loading. It automatically updates the content once it finishes rendering.

// Define a functional React component named 'loading'
const loading = () => {
	// You can add any UI inside loading component.
  return <div>Loading...</div>;
}

// Export the 'loading' component as the default export from this module
export default loading

Each route can have a loading state by adding a loading.js file inside a folder.

What if an unhandled error occurs during data fetching?

The error can completely break the application, which leads to bad user experience. Next.js provides a way to handle errors in server components.

Error.js

The error.js file is an automatic React error boundary. It handles error states in Next.js application when something fails.

'use client' // Tells Next.js to only run this component on the client side

// Define a functional React component named 'error' that takes 'error' and 'reset' as props
const error = ({ error, reset }) => {
	// Return a JSX block containing a 'div' with an error message and a 'Try again' button
	return (
		<div>
			<p><strong>Error:<strong></p>
			<button onClick={reset}>Try again</button>
		</div>
	);
};

// Export the 'error' component as the default export from this module
export default error

The error page has to be a client component, otherwise it would not work. Also, it gets two properties from Next.js: error (actual error) and reset (function to redo the last action).

Dynamic routes

Dynamic routes in Next.js allow for the creation of pages with URLs that can vary based on dynamic parameters.

Example of creating a dynamic route:

  1. Create, as example post folder, inside app directory.
  2. Inside post folder, create new folder in angled bracket notation. For example, [postID].
  3. Inside[postID] folder, add new file page.js with page layout.

URL example, with params:

https://example.com/post/4

Everything added after /post/ is going to be inferred as postID . Thus, it will be using page layout from [postID] folder.

To get passed value, such as postID , use props of page component.

// Define an asynchronous functional React component named 'page' that takes 'props' as an argument
const page = async (props) => {
	// Destructure the 'params' property from 'props'
	const { params } = props;
	// Get the 'postId' value from 'params'
	const postId = params.postId;

	// Fetch data from the specified API URL using the 'fetch' function, including the 'postId' value, and await the response
	const response = await fetch('api url goes here, including value:' + postId);

	// Parse the response as JSON and store it in the 'data' variable
	const data = await response.json();

	// Return a JSX block containing a 'div' that displays the fetched data
	return <div>{data}</div>;
};

// Export the 'page' component as the default export from this module
export default page

In Next.js dynamic routes, the name inside the brackets [postID] determines the parameter's name. To use a different name, simply change the folder name, e.g., [customName], and Next.js will use that as the parameter instead.

The framework supports searchParams for handling query parameters in URLs:

https://example.com/post/4?searchQuery=reactjs

The searchParams object is available as a prop in the page component, just like params object.

Next.js also allows to have URL with multiple params:

https://example.com/post/4/blue/yellow

However, the current folder structure will not work with that type of URL. To create a catch all segment folder, change folder name from [postID] to […postID].

Example of props from […postID] page component:

{
	params: { postId:['4', 'blue', 'yellow'] },
	searchParams: {}
}

In code example above, postId is now an array, with each item corresponding to a separate part of the URL after /post/. This allows to handle multiple parameters in the URL.