Thursday, May 2, 2024
HomeJavaScriptSubsequent.js Tutorial for Novices - LearnNextJS

Subsequent.js Tutorial for Novices – LearnNextJS


Subsequent.js is an open-source React-based front-end framework. Subsequent.js comes with options equivalent to File System Based mostly Routing, Server Facet Rendering (SSR), Static Website Generator (SSG), Incremental Static Regeneration (ISR), Picture Optimization, Code Splitting, Pre-fetching, Serverless Capabilities associated to efficiency, search engine optimization and effectivity of software growth. Options like Quick Refresh are pre-built. 

Many of those options need to be applied manually in different frameworks. Nonetheless, with Subsequent.js, you possibly can spend much less time implementing cutting-edge options and as an alternative deal with writing your software code.

Subsequent.js continues to be evolving, and its capabilities are expanded with each model improve. In truth, Subsequent is arguably essentially the most incessantly up to date framework on this – Node.js – class.

This tutorial explains the fundamental capabilities of Subsequent.js for individuals who have by no means touched Subsequent.js however are occupied with it or wish to use it sooner or later. 

💡The present (steady) model of Subsequent.js is 12.3

Here’s a abstract of what this tutorial will educate and canopy:

  • Methods to create a Subsequent.js venture
  • Methods to create Static information
  • Methods to create Dynamic information
  • Methods to set hyperlinks between pages
  • Structure settings in _app.js
  • Utilizing an API to fetch and render knowledge (getStaticProps, getServerSideProps)
  • Methods to use world.css and CSS modules
  • Methods to apply CSS with Tailwind CSS

With a view to set up Subsequent.js, it’s essential to obtain and set up Node.js in your machine.

Node.js download page
Node.js house web page

Supported OS are MacOS, Home windows (together with WSL), and Linux are supported.

Making a Subsequent.js Mission

Create a brand new Subsequent.js venture utilizing the npx command, or you should utilize yarn, pnpm, and so on.

% npx create-next-app@newest
Want to put in the next packages:
  create-next-app
Alright to proceed? (y) y
✔ What's your venture named? … new-app

// this may set up all of the required dependencies robotically

You may be requested for a venture identify, so enter any venture identify. Press Enter to proceed with the default identify. An arbitrary identify or my-app listing will probably be created within the listing the place the command was executed .

This tutorial doesn’t use TypeScript, however if you wish to use TypeScript, run npx create-next-app and append --typescript; this may robotically change information from JS to JSX.

Error throughout set up (macOS)

The next error is for OSX customers solely. It’s instantly associated to Command Line Instruments, so you might have to reinstall them totally.

Even when the set up course of goes to the top after which the npm run dev command is executed, the preliminary display of Subsequent.js is displayed, however the next error is displayed within the set up log.

gyp: No Xcode or CLT model detected!
gyp ERR! configure error 
gyp ERR! stack Error: `gyp` failed with exit code: 1
gyp ERR! stack     at ChildProcess.onCpExit (/usr/native/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:351:16)
gyp ERR! stack     at ChildProcess.emit (occasions.js:314:20)
gyp ERR! stack     at Course of.ChildProcess._handle.onexit (inner/child_process.js:276:12)
gyp ERR! System Darwin 19.6.0
gyp ERR! command "/usr/native/bin/node" "/usr/native/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /Customers/NextJS/Desktop/new-app/node_modules/fsevents
gyp ERR! node -v v14.7.0
gyp ERR! node-gyp -v v5.1.0
gyp ERR! not okay 

It means that there’s a drawback with the Command Line Instruments, so test the trail and delete it.

% xcode-select --print-path
/Library/Developer/CommandLineTools
% sudo rm -rf /Library/Developer/CommandLineTools

After deleting, you possibly can execute the next command to reinstall the Command Line Instruments:

% xcode-select --install

In the event you get the next error, “This software program can’t be put in as a result of it’s not at present obtainable from the software program replace server.”, it is advisable go to the Apple Developer website and seize the copy your self.

You possibly can then delete your new-app listing, and rerun npx create-next-app – the set up of your venture ought to be full with out hiccups.

Beginning the Subsequent.js growth server

When the set up is accomplished, the listing set by the venture identify will probably be created within the folder the place the command was executed.

└─ yocto-queue@0.1.0
✨  Carried out in 7.18s.

Initialized a git repository.

Success! Created new-app-next at /Customers/NextJS/Desktop/new-app-next

That is the listing we’ll be doing all the event work, so transfer to the venture listing new-app and execute the npm run dev command. In the event you test the logs after working the command, you possibly can see that the server is working at localhost:3000.

% cd new-app
% npm run dev

> new-app-next@0.1.0 dev
> subsequent dev

prepared - began server on 0.0.0.0:3000, url: http://localhost:3000
occasion - compiled shopper and server efficiently in 2.2s (165 modules)

Begin your browser and entry http://localhost:3000 to show the welcome display.

Welcome to Next.js
Subsequent.js Welcome Web page on First Launch

Subsequent.js set up is now up and working in your dev setting.

By checking the bundle.json file within the venture, you possibly can test the instructions that can be utilized throughout growth (dev, construct, and so on.) and the put in Subsequent.js model.

{
  "identify": "new-app",
  "model": "0.1.0",
  "non-public": true,
  "scripts": {
    "dev": "subsequent dev",
    "construct": "subsequent construct",
    "begin": "subsequent begin",
    "lint": "subsequent lint"
  },
  "dependencies": {
    "subsequent": "12.3.1",
    "react": "18.2.0",
    "react-dom": "18.2.0"
  },
  "devDependencies": {
    "eslint": "8.24.0",
    "eslint-config-next": "12.3.1"
  }
}

Welcome to Subsequent.js

This part introduces listing construction, web page creation, and dynamic naming.

Listing Construction

As soon as your venture is up and working, you possibly can test your app’s folder to look on the listing construction that Subsequent.js is utilizing.

4 directories, pages, types, node_modules, and public, can be found instantly after the venture is created. There are additionally three different information: README.md, bundle.json, and package-lock.json

There may be additionally a .subsequent listing and a .gitignore file with a .(dot) at the start.

The web page content material displayed within the browser is described within the index.js file within the /pages listing. You’ll write the core code of your software in this listing.

NextJS default directory structure
NextJS default listing construction

You may as well entry the information saved within the /public listing, instantly from the browser.

In different phrases, it’s potential to serve static information (equivalent to index.html) and render them with out touching the .js information.

CSS information are saved below the /types listing. You possibly can apply styling utilizing CSS information positioned below the general public listing and specifying it with a hyperlink tag as an alternative of a JavaScript bundle.

Updating index.js (Quick Refresh)

Any modifications you make to the index.js file will probably be robotically rendered within the browser so long as your server is working.

You possibly can attempt it your self by altering any of the traces within the default file.

/* <h1 className={types.title}>
Welcome to <a href="https://nextjs.org">Subsequent.js!</a>
</h1> */

<h1 className={types.title}>
Quick Refresh <a href="https://nextjs.org">Subsequent.js!</a>
</h1>

As a result of React is bundled into Subsequent.js by default, it’s pointless to import React.

In the event you run npm run dev, updating index.js will robotically replace the web page in your browser. It is a function Subsequent.js calls Quick Refresh

This very handy perform improves builders’ effectivity as a result of updates are mirrored instantly with out reloading the web page.

Hi there Subsequent.js

The following step is to take away every little thing contained in the index.js file and change it with the next:

export default perform PreRender() {
  return <h2>Subsequent.js Tutorial for Novices</h2>;
}

Upon getting achieved this, return to localhost:3000 and look at the web page supply.

web page supply for index.js

You possibly can see that the string “Subsequent.js Tutorial for Novices” is included within the web page supply. Since index.js is a JavaScript file, usually, the browser receives the JavaScript file, processes the JavaScript file, and shows its contents. In the event you have a look at the browser web page supply, you possibly can see that the browser instantly receives HTML info (h2 tag). 

It’s because Subsequent.js does pre-rendering on the server facet earlier than sending it to the browser. For the reason that HTML info is obtained as is, there isn’t any must course of JavaScript on the browser facet to show “Subsequent.js Tutorial for Novices”. By default, Subsequent.js does pre-rendering on each web page. Pre-Rendering is a perform that creates a web page prematurely on the Subsequent.js facet (Server-Facet Rendering) and sends the created web page to the shopper earlier than processing with JavaScript on the shopper facet.


To additional illustrate this idea, we will create a brand new React venture and examine the distinction. Take the “Subsequent.js tutorial” perform above and place it in your React venture’s index.js file. Then entry the URL to render the perform. It can work because it does in Subsequent, however should you examine the web page supply after which seek for the string you entered, it won’t be proven within the web page supply. It’s because React makes use of Consumer-Facet Rendering.

Subsequent.js gives three alternative ways to pre-render information, together with Static Era (SSG), Incremental Static Regeneration (ISR), and Server Facet Rendering (SSR).

Making a Web page (Static Routing)

With Subsequent.js, web page routing is about robotically (File System Based mostly Routing), so should you go forward and create a brand new file known as contact.js in your /pages listing, you possibly can then entry that file by going to http://localhost:3000/contact instantly.

export default perform Contact() {
  return <h2>My contact handle is: root@localhost</h2>;
}

And we will verify that it really works:

contact.js rendered with out handbook routes

Subsequent.js doesn’t use React Router.

Capabilities will be written in quite a few methods, so it’s as much as you resolve which one is you want the most effective.

perform Contact() {
  return (
    <h2>Contact Us</h2>
  )
}

export default Contact

// Arrow perform
const Contact = () => {
  return (
    <h2>Contact Us</h2>
  )
}

export default Contact

What about 404 pages? With the present configuration, something that isn’t the basis listing (/) or the pages we’ve created – /contact – will return a 404 error.

404 not discovered

Let’s create a new folder inside our /pages listing known as weblog, after which create a file inside that listing known as publish.js.

export default perform BlogPost() {
  return <h2>The title for my #1 weblog publish</h2>;
}

When you do, you possibly can go to http://localhost:3000/weblog/publish and the web page will probably be rendered, showcasing how Subsequent.js makes use of Nested Routes for web page/listing hierrarchy.

publish.js

Creating Dynamic Information (Dynamic Routing)

Let’s study Dynamic Routing in Subsequent.

For instance, if in case you have an eCommerce retailer, you’re going to have a merchandise web page, and inside the scope of that web page additionally, you will have the precise merchandise themselves.

Must you be making a cellphone.js, pc.js file each time you add a brand new product?

Due to Dynamic Routing, we will create a single file after which serve request content material primarily based on the URL itself.

First, let’s create a brand new folder known as /merchandise in our /pages folder, after which create a file known as [name].js within the folder we simply created.

export default perform ProductName() {
  return <h2>Viewing Product: </h2>;
}

Now you can go to http://localhost:3000/merchandise/pc and change pc with any string, and the web page will probably be rendered utilizing the capabilities outlined within the [name].js file.

Dynamic Routing in Next.js
Dynamic Routing in Subsequent.js

Even should you change the URL to cellphone or pill, the identical “Viewing Product: ” is displayed, so the subsequent step is to make use of the useRouter Hook so we will dynamically show the product string contained in the web page content material. By utilizing useRouter Hook, you possibly can dynamically change the content material of the web page in accordance with the accessed URL. Utilizing the useRouter Hook, you possibly can entry the router object that has details about routing from the perform element.

The useRouter Hook imports from subsequent/router:

import { useRouter } from "subsequent/router";

export default perform ProductName() {
  const router = useRouter();
  return <h2>Viewing Product: {router.question.identify}</h2>;
}

The character string included within the URL will be obtained from router.question.identify.

Now you can refresh the web page to see the brand new end result:

useRouter Hook
NextJS useRouter Hook

We will additionally use console.log to test the info saved within the router.question.

import { useRouter } from "subsequent/router";

export default perform ProductName() {
  const router = useRouter();
  console.log(router.question);
  return <h2>Viewing Product: {router.question.identify}</h2>;
}

In the event you test the console of the browser’s developer instruments, you possibly can see that the identify is included within the object, as proven beneath:

identify: "pc"
[[Prototype]]: Object

Additionally, even should you add a parameter to the URL, you may get the worth of the added parameter from router.question.

You possibly can attempt it with: http://localhost:3000/merchandise/pc?gpu=amd

question string parameters

As well as, Dynamic Routing can be utilized even when the web page hierarchy is deep.

Create a [name] listing below the merchandise listing. 

Then, create a [gpu].js file below the [name] listing.

import { useRouter } from "subsequent/router";

export default perform ProductGPU() {
  const router = useRouter();
  console.log(router.question)
  return <h2>Viewing Product: {router.question.identify} with {router.question.gpu} GPU</h2>;
}

Now you can entry http://localhost:3000/merchandise/pc/amd to see the way it works.

query string deep hierarchy
question string deep hierarchy

The [gpu].js file can be written utilizing the destructuring task.

import { useRouter } from "subsequent/router";

export default perform ProductGPU() {
  const router = useRouter();
  const { identify, gpu } = router.question
  return <h2>Viewing Product: { identify } with { gpu } GPU</h2>;
}

Linking to Pages

In Subsequent, managing hyperlinks is finished utilizing the Hyperlink element.

We use it as you’ll think about – to maneuver from one web page to the subsequent. And seeing how we now have so many pages already, we would as nicely create hyperlinks to them since there isn’t any different option to entry them except you share them instantly.

Right here is a straightforward perform to allow us to navigate to the contact.js web page.

import Hyperlink from "subsequent/hyperlink";

export default perform Dwelling() {
  return (
    <div>
      <ul>
        <li>
          <Hyperlink href="https://learnnextjs.com/contact">
            <a>Contact</a>
          </Hyperlink>
        </li>
      </ul>
      <h2>Welcome to my homepage!</h2>
    </div>
  );
}

The Contact string has an a tag, however if you wish to set a CSS class, use the className attribute within the a tag as an alternative of the Hyperlink tag. 

In the event you save that and open it within the browser, you possibly can click on on the Contact hyperlink and see that Subsequent preloaded the web page, and also you had been capable of entry it immediately and not using a refresh.

Creating hyperlinks utilizing the Hyperlink element

You may as well take out the <Hyperlink /> element totally after which use a standard HTML hyperlink; it is best to instantly have the ability to see that with out the Hyperlink element, the web page refreshes quite than masses immediately.

Since we talked about Dynamic Routing already, it’s potential to set the href worth to make use of Objects in addition to paths.

import Hyperlink from 'subsequent/hyperlink';

export default perform Dwelling() {
  return (
    <div>
      <ul>
        <li>
          <Hyperlink
            href={{
              pathname: "https://learnnextjs.com/contact",
              question: { identify: 'admin' },
            }}
          >
            About
          </Hyperlink>
        </li>
      </ul>
      <h2>Welcome to my homepage!</h2>
    </div>
  );
}

This similar precept will be utilized through the use of an array to outline the ultimate vacation spot for every web page, and the identical idea of loading pages with out refreshing them is utilized.

import Hyperlink from "subsequent/hyperlink";

const merchandise = [{ name: "phone" }, { name: "computer" }, { name: "tablet" }];
export default perform Dwelling() {
  return (
    <div>
      <ul>
        {merchandise.map((product) => {
          return (
            <li key={product.identify}>
              <Hyperlink href={`/merchandise/${product.identify}`} >
                <a>{product.identify}</a>
              </Hyperlink>
            </li>
          );
        })}
        <li>
          <Hyperlink href="https://learnnextjs.com/contact">
            <a>Contact</a>
          </Hyperlink>
        </li>
      </ul>
      <h2>Welcome to my homepage!</h2>
    </div>
  );
}

You now have a purposeful option to hyperlink to your pages dynamically:

Linking to a number of pages

Understanding prefetch

Along with href, the Hyperlink element props embrace prefetch, and so on.

By default, prefetch is about to true. The hyperlink robotically downloads the linked JavaScript file when it enters the browser’s viewport. Since it’s unattainable to test the operation within the growth setting (npm run dev), we’ll run it within the manufacturing setting (npm run construct && npm run begin). 

npm run construct builds the created venture. npm run begin will do the construct, and the manufacturing server will begin.

Ensure you save the file beneath after which do the construct and begin instructions.

After, open localhost:3000, however don’t scroll down earlier than you open Developer Instruments -> Community. When you do, you possibly can scroll down.

import Hyperlink from "subsequent/hyperlink";

const merchandise = [{ name: "phone" }, { name: "computer" }, { name: "tablet" }];
export default perform Dwelling() {
  return (
    <div>
      <ul>
        {merchandise.map((product) => {
          return (
            <li key={product.identify}>
              <Hyperlink href={`/merchandise/${product.identify}`} >
                <a>{product.identify}</a>
              </Hyperlink>
            </li>
          );
        })}
        <li fashion={{ marginTop: '100em' }}>
          <Hyperlink href="https://learnnextjs.com/contact">
            <a>Contact</a>
          </Hyperlink>
        </li>
      </ul>
      <h2>Welcome to my homepage!</h2>
    </div>
  );
}

As a result of our margin from the highest is about to 100em, it is advisable scroll down the web page, and as you attain the Contact hyperlink – it is best to see that the web page prefetched the contact.js doc.

It’s additionally potential to flag prefetch as false, on this case, the file will solely be requested everytime you hover over the hyperlink.

<Hyperlink href="https://learnnextjs.com/contact" prefetch={false}>

Structure Construction

When creating an software with a number of pages, some web page components, equivalent to Headers and Footers, will (virtually) at all times stay the identical. Moreover, designing sure content material areas individually means you received’t must replace pages individually whenever you make huge modifications. So let’s create a fundamental structure construction.

First, create a elements listing (in your app listing) and create a Structure.js file to set the default structure for your complete software.

import Header from './header';
import Footer from './footer';

export default perform Structure({ youngsters }) {
  return (
    <>
      <Header />
      <predominant>{youngsters}</predominant>
      <Footer />
    </>
  );
}

In the identical listing, create header.js and footer.js information. You may as well add a preliminary header fashion by linking to a few of the pages we’ve already created.

import Hyperlink from 'subsequent/hyperlink';

export default perform Header() {
  return (
    <ul>
      <li>
        <Hyperlink href="https://learnnextjs.com/">
          <a>Dwelling</a>
        </Hyperlink>
      </li>
      <li>
        <Hyperlink href="https://learnnextjs.com/contact">
          <a>Contact</a>
        </Hyperlink>
      </li>
    </ul>
  );
}

And in addition a fundamental footer:

export default perform Footer() {
  return (
    <div>
      <p>&copy; 2022</p>
    </div>
  );
}

After creating the Structure.js file and associated information, open the _app.js file (inside /pages folder), import the Structure element, and apply the settings as proven beneath. 

The _app.js file is the appliance’s entry level, and this file wraps all pages. It may be used when making use of frequent elements to all pages.

import '../types/globals.css';
import Structure from '../elements/structure';

export default perform MyApp({ Part, pageProps }) {
  return (
    <Structure>
      <Part {...pageProps} />
    </Structure>
  );
}

Now you can go to localhost:3000 to see the modifications.

Header and Footer elements utilized

All of the hyperlinks are working as supposed.

Preserving the State

Do you perceive the distinction is between setting Structure in index.js and contact.js as an alternative of setting it in _app.js? Let’s have a look at why it’s necessary.

Go forward and alter your index.js and contact.js information as proven beneath:

import Structure from '../elements/structure';

export default perform Dwelling() {
  return (
    <Structure>
      <h2>Welcome to my homepage</h2>
    </Structure>
  );
}
import Structure from '../elements/structure';

export default perform Contact() {
  return (
    <Structure>
      <h2>My contact handle is: root@localhost</h2>
    </Structure>
  );
}

Then restore the _app.js file to its unique state.

import '../types/globals.css';

export default perform MyApp({ Part, pageProps }) {
  return (
    <Part {...pageProps} />
  );
}

In the event you test the browser’s response, the positioning’s look won’t change, and the preliminary performance continues to be there. Even when you don’t set Structure in _app.js, the above settings merely work. Nonetheless, the distinction in conduct turns into clear when you’ve gotten variables equivalent to useState in your Structure information.

Let’s apply the useState Hook within the footer.js file and create a easy button counter:

import { useState } from 'react';

export default perform Footer() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>{rely}</p>
      <div>
        <button onClick={() => setCount(rely + 1)}>Click on me!</button>
      </div>
      <p>&copy; 2022</p>
    </div>
  );
}

Click on the button to extend the rely quantity.

NextJS button counter
Counter within the footer.

Ensure you clicked it a couple of instances and now navigate to the Contact web page.

nextjs counter reset
Transferring to a special web page, the counter reset again to 0

Every little thing works tremendous, besides the counter has been reset again to zero.

Let’s go forward and unset the Structure from the index.js and contact.js information, and reassign it to the _app.js file.

import '../types/globals.css';
import Structure from '../elements/structure';

export default perform MyApp({ Part, pageProps }) {
  return (
    <Structure>
      <Part {...pageProps} />
    </Structure>
  );
}

Click on the button a couple of instances, after which change the web page by clicking on Contact or no matter else web page you’re engaged on.

As you’ll see, the State of the counter is retained even should you change pages.

next.js preserving state

As such, defining Structure in _app.js helps us wrap your complete structure with out dropping state, equivalent to enter values.

Completely different Structure for Every Web page

In the event you’d like to make use of a special structure for varied pages, the best way to take action is thru the getLayout property.

Import the Structure element in contact.js and set the getLayout property to a perform.

import Structure from '../elements/structure';

export default perform Contact() {
  return <h2>My contact handle is: root@localhost</h2>;
}

Contact.getLayout = perform getLayout(web page) {
  return <Structure>{web page}</Structure>
};

Replace _app.js as proven beneath. If the Part has the getLayout property, the getLayout perform set in contact.js will probably be executed, and if there isn’t any getLayout, the element will probably be returned as is.

export default perform MyApp({ Part, pageProps }) {
  const getLayout = Part.getLayout || ((web page) => web page);
  return getLayout(<Part {...pageProps} />);
}

In the event you go to localhost:3000/contact you’ll see that the Header and Footer are displayed, nevertheless, as a result of getLayout has not been set elsewhere, different pages won’t inherit both.

As such, should you’d like to make use of a special structure for every web page, it’s a must to import Structure after which set getLayout explicitly.

Picture Show

Subsequent has a built-in Picture element for displaying pictures. For this demo, you possibly can take any picture you want, after which reserve it within the public listing.

To make use of the Picture element, it is advisable import it from subsequent/picture, and set the width and peak of props.

import Picture from "subsequent/picture";

export default perform Dwelling() {
  return (
    <div>
      <h2>Welcome to my homepage</h2>
      <Picture src="https://learnnextjs.com/demo.jpeg" width={500} peak={300} />
    </div>
  );
}

/* consider we're working with Structure being outlined in _app.js */

In the event you save this and test the homepage, the picture ought to present up:

next/image component
subsequent/picture element

An alternate is to make use of a picture from an exterior website, equivalent to Pexels or Unsplash:

import Picture from "subsequent/picture";

export default perform Dwelling() {
  return (
    <div>
      <h2>Welcome to my homepage</h2>
      <Picture
        src="/https://pictures.pexels.com/pictures/9832430/pexels-photo-9832430.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1demo.jpeg"
        width={500}
        peak={300}
      />
    </div>
  );
}

In the event you test the homepage, it is best to see the next error:

Unhandled Runtime Error

Error: Invalid src prop (https://pictures.pexels.com/pictures/9832430/pexels-photo-9832430.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1demo.jpeg) on subsequent/picture, hostname “pictures.pexels.com” is just not configured below pictures in your subsequent.config.js

This error comes up as a result of the exterior area has not been registered within the subsequent.config.js file.

/** @sort {import('subsequent').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  pictures: {
    domains: ["images.pexels.com"],
  },
};

module.exports = nextConfig;

When you replace subsequent.config.js it is advisable rerun npm run dev to reload the config. Your exterior pictures will seem on the pages the place you’ve gotten positioned them.

It’s essential to set meta tags for engines like google to grasp the construction of your website. In Subsequent, meta tags are dealt with utilizing the Head element.

Right here is an instance of setting a web page title:

import Hyperlink from 'subsequent/hyperlink';
import Head from 'subsequent/head';

export default perform Dwelling() {
  return (
    <div>
      <Head>
        <title>My web page title</title>
      </Head>
      <ul>
        <li>
          <Hyperlink href="https://learnnextjs.com/about">
            <a>About</a>
          </Hyperlink>
        </li>
      </ul>
      <h1>Hi there Subsequent.js</h1>
    </div>
  );
}

You possibly can reload localhost:3000 to verify, and the title tag can be proven within the web page supply. Now, the Head element gives many extra methods to specify search engine optimization tags, like so:

<Head>
  <title>My web page title</title>
  <meta identify="description" content material="Description about my website." />
  <meta property="og:title" content material="Social Media Title" />
  <meta property="og:description" content material="Social Media Description" />
</Head>

Within the above instance, the worth was set instantly, however the title have to be proven dynamically on particular person pages (weblog, merchandise, and so on.). 

Usually, settings are made utilizing the meta info of particular person pages included in props, however we will additionally use arrays that we outlined in an earlier instance of product pages.

import Hyperlink from 'subsequent/hyperlink';
import Head from 'subsequent/head';

const merchandise = [{ name: "phone" }, { name: "computer" }, { name: "tablet" }];

export default perform Dwelling() {

  return (
    <div>
      <Head>
        <title>{merchandise[0].identify}</title>
        <meta identify="description" content material={merchandise[0].identify} />
        <meta property="og:title" content material={merchandise[0].identify} />
        <meta
          property="og:description"
          content material={merchandise[0].identify}
        />
      </Head>
     </div>
);
}

Importing Knowledge from an API (SSG, SSR)

To this point, we’ve checked out many fundamental Subsequent.js ideas, however one of many predominant attracts behind Subsequent and plenty of comparable frameworks is the flexibility to import exterior knowledge from an API. And, on high of that, have the ability to serve that knowledge by way of strategies equivalent to Server-Facet Rendering, Static Website Era, and Incremental Static Regeneration.

For this phase, we’re going to use the JSONPlaceholder API.

JSON Placeholder API

We’ll test the right way to show it on the browser utilizing the info obtained from the surface. I’ll use the JSONPlaceholder service to get the info.

The aim is to make use of this API to fetch the placeholder knowledge and show it in our Subsequent.js software.

As talked about earlier, Subsequent.js has 3 strategies (SSG, SSR, ISR) for fetching knowledge and Pre-Rendering on the server facet. For this tutorial, we’ll deal with 2 completely different strategies:

  • getStaticProps (Static Website Era)
  • getServerSideProps (Server-Facet Rendering)

getStaticProps fetches knowledge solely as soon as at construct time with Static Website Era (SSG) to pre-render the web page. getServerSideProps does Server-Facet Rendering (SSR), which acquires and pre-renders knowledge on the server facet when accessed from the shopper. getStaticProps and getServerSideProps can’t be executed in any file, solely within the web page file and never within the element file.

SSG is used when pages equivalent to weblog articles usually are not incessantly added or up to date. SSR can be utilized when the content material displayed modifications relying on the request, equivalent to a search web page. SSG creates an HTML web page at construct time and caches it on the CDN (Content material Supply Community), so the web page is displayed instantly. 

Is it potential to get knowledge from exterior sources solely on the server facet? 

It’s potential to get knowledge on the shopper facet as an alternative of the server facet. Subsequent.js gives a React Hook library known as SWR (stale-while-revalidate) that can be utilized to accumulate knowledge on the shopper facet, so on this phase, we will even have a look at the right way to purchase knowledge utilizing SWR.

In the end, the aim of SSR, SSG, ISR, and SWR is to hurry up your software and the tempo at which you develop and implement new options.

Methodology #1 – getServerSideProps

Create a brand new posts listing and create an index.js file.

export default perform index({ posts }) {
  return (
    <div>
      <h2>Posts API</h2>
    </div>
  );
}

export async perform getServerSideProps() {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts`);
  const posts = await res.json();
  console.log(posts);
  return { props: { posts } };
}

In the event you open localhost:3000/posts – you will note that nothing occurred.

In truth, regardless of having specified console.log(posts) – the info fetched from the API is not proven within the Developer Console (Browser).

It’s because getServerSideProps renders on the server facet.

However should you go to your Terminal the place your dev setting is working, you will note that the API knowledge is proven there.

nextjs server side rendering terminal

Now that we now have confirmed that the info is being pulled, we will use the map perform to broaden and current the info on our web page.

export default perform index({ posts }) {
  return (
    <div>
      <h2>Posts API</h2>
      <ul>
        {posts.map((publish) => {
          return <li key={publish.id}>{publish.title}</li>;
        })}
      </ul>
    </div>
  );
}

export async perform getServerSideProps() {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts`);
  const posts = await res.json();
  console.log(posts);
  return { props: { posts } };
}

In the event you test your browser, the total listing of posts is now rendered on the web page.

POST listing is displayed

Vital to notice that getServerSideProps will be executed in web page elements, however not in common elements. You possibly can as an alternative, purchase the API knowledge within the web page element and go the acquired knowledge to different elements in props.

Creating and Displaying Particular person Pages

The following step is to retrieve particular person posts and show them utilizing Dynamic routing.

Create a [post].js file below /posts.

export default perform publish() {
  return <h2>Posts API</h2>;
}

Subsequent, we’ll import the Hyperlink element and replace the show construction in order that particular person hyperlinks (posts) will be clicked on.

import Hyperlink from "subsequent/hyperlink";

export default perform index({ posts }) {
  return (
    <div>
      <h2>Posts API</h2>
      <ul>
        {posts.map((publish) => {
          return (
            <li key={publish.id}>
              <Hyperlink href={`/posts/${publish.id}`}>
                <a>{publish.title}</a>
              </Hyperlink>
            </li>
          );
        })}
      </ul>
    </div>
  );
}

At this level, we’ve created a path to the person posts, however should you go to localhost:3000/posts/1 – the web page will probably be clean outdoors of the default Structure.

Acquiring the Particular person IDs

You will want to jot down a separate getServerSideProps perform to get the ID of the person publish within the API. As soon as once more, this renders on the server facet, and each time you entry a singular ID, you’ll get a { publish: '1' } response in your Terminal.

export async perform getServerSideProps({ params }) {
  console.log(params);
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts`);
  const posts = await res.json();
  return { props: { posts } };
}

We acquired the ID worth in params as a result of we used dynamic routing, however you can even get values ​​equivalent to req, res, and question along with params. If you wish to test these values, put context within the argument of getServerSideProps and test with console.log(context)

req is an abbreviation for request, and you can even test the shopper info and header info that has been accessed.

export async perform getServerSideProps(context) {
  console.log(context);
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts`);
  const posts = await res.json();
  return { props: { posts } };
}

For newbies, even should you have a look at the context, there’s an excessive amount of info to course of, so don’t fear an excessive amount of about it. 

Simply consider the assorted kinds of info you may get like this.

Get the Knowledge for Particular person IDs

Now we’ll seize the knowledge contained in the ID saved in params.

export default perform publish({ publish }) {
  return (
    <div>
      <h1>Put up ID: {publish.id}</h1>
      <h2>{publish.title}</h2>
      <p>{publish.physique}</p>
    </div>
  );
}

export async perform getServerSideProps({ params }) {
  const id = params.publish;
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  const publish = await res.json();
  return { props: { publish } };
}

Now, should you go to localhost:3000/posts/42 , you’ll see the info being fetched and rendered.

Obtaining Data for Individual IDs
Acquiring Knowledge for Particular person IDs

ID Not Discovered (404)

What occurs when a request is made to an ID that doesn’t exist within the API?

On this case, JSONPlaceholder has a restrict of 100 posts, and should you go to localhost:3000/posts/101 it would return a clean web page.

Let’s use console.log to test what sort of knowledge is obtained when an ID that doesn’t exist is accessed.

export async perform getServerSideProps({ params }) {
  const id = params.publish;
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  const publish = await res.json();
  console.log(publish);
  return { props: { publish } };
}

In the event you have a look at your Terminal, you possibly can see that it’s an empty object {}.

When executing getServerSideProps, an object with props was returned in return, however you can even return an object with notFound along with props. 

notFound can have true and false values, however setting it to false will end in an error.

return {
  notFound: true,
};

Since it’s confirmed that will probably be an empty object accessed with an ID that doesn’t exist, set it in order that an object with notFound is returned when judging an empty object.

export async perform getServerSideProps({ params }) {
  const id = params.publish;
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  const publish = await res.json();
  if (!Object.keys(publish).size) {
    return {
      notFound: true,
    };
  }
  return { props: { publish } };
}

In the event you go to localhost:3000/posts/101 once more, you will note a 404 error.

404 Web page not Discovered

Methodology #2 – getStaticProps

getServerSideProps will get knowledge on the server facet for every request, however getStaticProps will get knowledge on the server facet at construct time. For the reason that code executed by getStaticProps is just not included within the JavaScript bundle code despatched to the shopper facet, it’s also not potential to test the contents of the code on the shopper facet.

Altering to getStaticProps

Change getServerSideProps to getStaticProps within the index.js file within the posts listing.

export async perform getStaticProps() {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts`);
  const posts = await res.json();
  return { props: { posts } };
}

Even whereas working npm run dev – the change of methodology was utilized to the /posts index web page.

Now change from getServerSideProps to getStaticProps within the [post].js file as nicely.

export async perform getStaticProps({ params }) {
  const id = params.publish;
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  const publish = await res.json();
  return { props: { publish } };
}

Within the case of index.js, the info was displayed in the identical means simply by altering from getServerSideProps to getStaticProps, however an error is returned within the [post].js file:

getStaticPaths is required for dynamic SSG pages
getStaticPaths is required for dynamic SSG pages

The error states that getStaticPaths is required for dynamic SSG pages.

Getting the Path Info with getStaticPaths

Let’s add the getStaticPaths methodology as proven within the error message. 

Within the getStaticPaths methodology, it is advisable create a path listing of pages to be created at construct time and return with paths. Like getStaticProps, getStaticPaths can be executed on the server facet, so it’s not included within the JavaScript bundle code despatched to the shopper facet, so it can’t be executed on the shopper facet and the contents of the code can’t be seen.

export async perform getStaticPaths() {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts`);
  const posts = await res.json();
  const paths = posts.map((publish) => `/posts/${publish.id}`);
  return {
    paths,
    fallback: false,
  };
}

Here’s a abstract of what’s taking place within the above perform:

  1. Entry JSONPlaceholer to get a listing of posts,
  2. broaden the acquired posts with the map perform,
  3. extract the id of particular person pages,
  4. and create a path /posts/${publish.id}.

If you may get the trail info of the person web page with getStaticPaths, the web page will probably be displayed with out error even should you entry the person web page.

The perform can be written as follows:

export async perform getStaticPaths() {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts`);
  const posts = await res.json();
  const paths = posts.map((publish) => ({
    params: { publish: publish.id.toString() },
  }))
  return {
    paths,
    fallback: false,
  };
}

getStaticPaths has the position of passing the trail info of the web page to be created, so if there isn’t any getStaticPaths, there isn’t any path info, so an error just like the one above will happen.

fallback Settings

The fallback will be set to true or false; if set to false, a 404 error will probably be displayed when accessing a web page aside from an present one.

If fallback is about to true, a server error display will probably be displayed.

TypeError: Cannot read properties of undefined (reading 'id')
fallback: true;

If a web page that didn’t exist on the time of construct is added, by setting fallback to true, when the web page is accessed, the web page is created, and the created web page will be returned to the person.

Utilizing the router’s isFallback property, “Loading…” will be displayed on the display earlier than the web page is created. When the web page is created, “Loading…” will disappear from the display and show the created web page. “Loading…” is displayed for a second. isFallback is true at first, however when the web page is created, it turns into false, and “Loading…” disappears.

if (router.isFallback) {
    return <div>Loading...</div>
}

In the event you entry a web page that has not been added, the error “Unhandled Runtime Error: Didn’t load static props” will probably be displayed on the display after “Loading…” is displayed.

You may as well set “blocking” for fallback, and should you set blocking, it would wait till the web page is created, so errors won’t be displayed. The worth of isFallback stays false when blocking, so there isn’t any must set router.isFallback, and when blocking, “Loading…” won’t be displayed on the display.

Executing npm run construct

GetStaticProps create static pages when constructing, so let’s run npm run construct

You possibly can test from the construct log that the static pages are generated in real-time.

% npm run construct

information  - Producing static pages (108/108)
information  - Finalizing web page optimization  

Route (pages)                              Measurement     First Load JS
┌ ○ /                                      4.27 kB        84.2 kB
├ ● /posts (309 ms)                        372 B          80.3 kB
└ ● /posts/[post] (6364 ms)                329 B          80.3 kB
    ├ /posts/1
    ├ /posts/2
    ├ /posts/3
    └ [+97 more paths]

In our state of affairs, as a result of the API we’re utilizing has 100 posts inside it, the construct command will create 100 .HTML (static) information and 100 .JSON information.

You possibly can confirm this by going to .subsequent/server/pages/posts.

Lastly, should you execute npm run dev, all of the information will probably be deleted. For this reason it’s necessary to separate your dev setting from the manufacturing setting.

Retrieving Knowledge with SWR (Consumer)

SWR is a state-while-revalidate React Hooks library for knowledge fetching on the shopper facet. It’s developed and maintained by Vercel. Let’s set up it first and have a look at some examples of the right way to use it.

% npm set up swr

added 1 bundle, and audited 272 packages in 1s

To make use of it, import useSWR from swr and set the important thing to the primary argument of useSWR Hook and the fetcher perform to the second argument. Set the URL for the important thing. Value noting that since not solely knowledge but additionally errors are returned, error dealing with will be achieved simply.

import useSWR from 'swr'

const { knowledge, error } = useSWR(
  'https://jsonplaceholder.typicode.com/posts',
  fetcher
);

Additionally it is potential to set choices within the third argument.

The fetcher perform describes the info acquisition course of utilizing the URL of the primary argument.

const fetcher = (url) => fetch(url).then((res) => res.json());

Utilizing these processes, the index.js file within the /posts listing will be specified as proven beneath.

An error message will probably be displayed on the browser if an error is returned. For the reason that worth of information is undefined whereas knowledge is being acquired, the string “Loading…” is displayed within the browser.

import useSWR from "swr";

const fetcher = (url) => fetch(url).then((res) => res.json());

export default perform index() {
  const { knowledge, error } = useSWR(
    "https://jsonplaceholder.typicode.com/posts",
    fetcher
  );

  if (error) return <div>Didn't load.</div>;
  if (!knowledge) return <div>Loading...</div>;

  return (
    <div>
      <h2>Posts API utilizing SWR</h2>
      <ul>
        {knowledge.map((publish) => {
          return <li key={publish.id}>{publish.title}</li>;
        })}
      </ul>
    </div>
  );
}

The knowledge obtained from JSONPlaceholder will probably be displayed should you test your browser. 

On this means, you should utilize SWR to retrieve knowledge on the shopper facet.

Fetching API using SWR
Fetching API utilizing SWR

Within the case of information acquisition processing on the shopper facet, SWR is just not required, and it’s potential to accumulate knowledge utilizing useState, useEffect, and so on. Along with this, SWR has varied capabilities, equivalent to caching knowledge primarily based on the important thing of the primary argument of useSWR, and robotically re-acquiring knowledge whenever you take away the cursor from the browser and click on the browser once more.

By checking the community tab of the browser’s developer instruments, you possibly can verify that knowledge reacquisition is robotically carried out.

Setting setting variables

.env.native file

You should use the .env.native file if you wish to use setting variables as an alternative of writing values instantly within the code, equivalent to API_KEY and database info.

You possibly can create a .env.native file in your venture listing and set the setting variables as follows.

API_KEY=apikey
DB_HOST=localhost
DB_USER=person
DB_PASS=password

If you wish to use it in your code, you may get the values ​​with course of.env.API_KEY and course of.env.DB_HOST.

If you wish to use it with getServerSideProps, you are able to do it like so:

export async perform getServerSideProps() {
  const api_key = course of.env.API_KEY;
  const end result = await fetch(
    `https://api.url/?api_key=${api_key}`
  );

Getting values ​​from the .env.native file is feasible when executed on the server facet, equivalent to whenever you’re utilizing getServerSideProps, however if you wish to apply it to client-side, it is advisable add NEXT_PUBLIC_.

NEXT_PUBLIC_API_KEY=apikey
API_KEY=apikey
DB_HOST=localhost
DB_USER=person
DB_PASS=password

And it may be known as utilizing process_env.NEXT_PUBLIC_API_KEY out of your app code.

useEffect(() => {
 const fetchData = async () => {
 const api_key = course of.env.NEXT_PUBLIC_API_KEY;

If the identical setting variable is used however will be obtained in a single course of however not one other, test whether or not the method is carried out on the server or the shopper facet. In the event you can’t inform the distinction, attempt setting NEXT_PUBLIC_ within the app code and check it.

In the event you add an setting variable and the worth is undefined, re-run the npm run dev command.

Different setting variables

Along with .env.native, you possibly can create information named .env.growth (for dev setting) and env.manufacturing (for the manufacturing setting) to avoid wasting setting variables. 

In the event you add setting variables with the identical identify to .env.native and .env.growth in your growth setting and set completely different values, they are going to be overwritten by .env.native

The goes for .env.manufacturing which is overridden by .env.native.

The .env.native file is specified within the .gitignore file, so it won’t be uploaded even should you push it with git.

# native env information
.env.native
.env.growth.native
.env.check.native
.env.manufacturing.native

Within the .gitignore file, you possibly can see the information .env.growth.native and .env.manufacturing.native are completely different from the information defined earlier. This can be utilized in growth and manufacturing environments respectively, and the worth you set will take priority over .env.native.

You may as well use .env.check and .env.check.native information for testing.

Within the dev setting, .env.growth.native has the best precedence.

Making use of CSS with the worldwide.css file

CSS in Subsequent.js will be utilized in a number of methods. It can be utilized utilizing globals.css within the types listing. Any identify aside from world.css can be utilized.

The globals.css file is imported within the _app.js file below the pages listing in any Subsequent.js venture.

Go forward and open the worldwide.css file and apply the next fashion:

.home-heading {
  colour: orange;
}

Then apply the .home-heading class to your h2 utilizing className.

export default perform Dwelling() {
  return (
    <div>
      <h2 className="home-heading">Welcome to my homepage</h2>
    </div>
  );
}

In the event you test your browser, you possibly can see that the heading parameters laid out in globals.css have been utilized.

Styling with world.css

An error will happen should you attempt to Import world.css wherever aside from _app.js.

So, what to do if you wish to apply customized CSS to a particular element?

Making use of CSS with module.css information

Everytime you create a brand new Subsequent.js venture – in your /types listing, you can find two information: world.css and Dwelling.module.css. That is often known as CSS Modules for styling. The best way it really works is {that a} Module will apply its syntax at the start of the category identify, so even should you use the identical class identify elsewhere – it would haven’t any impact aside from on the customized element that you just’re utilizing the CSS Module on.

world.css will be imported from _app.js and utilized to your complete software. 

The {identify}.module.css is used to use CSS to particular elements. 

Right here is the way you import customized modules:

import types from "../types/Dwelling.module.css";

Imported types develop into objects and set lessons are registered as object properties. 

If you wish to apply a category utilizing the types imported from the Dwelling.module.css file, you are able to do the next:

import types from "../types/Dwelling.module.css";

export default perform Dwelling() {
  return (
    <div>
      <h2 className={types.heading}>Welcome to my homepage</h2>
    </div>
  );
}

You possibly can place a customized fashion in your .heading in Dwelling.module.css.

.heading {
  background-color: indigo;
  colour: #fff;
  padding: 1.5rem;
  border: 1px dotted yellow;
}
CSS Modules in Next.js
CSS Modules in Subsequent.js

You possibly can confirm the customized class names by putting console.log(types) earlier than the Dwelling() perform, then open Console out of your Browser’s developer instruments.

{
    "heading": "Home_heading__BTwrO",
    "container": "Home_container__bCOhY",
    "predominant": "Home_main__nLjiQ",
    "footer": "Home_footer____T7K",
    "title": "Home_title__T09hD",
    "description": "Home_description__41Owk",
    "code": "Home_code__suPER",
    "grid": "Home_grid__GxQ85",
    "card": "Home_card___LpL1",
    "emblem": "Home_logo__27_tb"
}

Utilizing Tailwind CSS with Subsequent.js

You may as well observe alongside the official Tailwind CSS docs on the right way to set up Tailwind for Subsequent.js initiatives.

Let’s set up the bundle:

% npm set up -D tailwindcss@newest postcss@newest autoprefixer@newest

added 41 packages, modified 1 bundle, and audited 271 packages in 5s

After putting in the bundle, create the Tailwind CSS configuration file:

% npx tailwindcss init -p
  
Created Tailwind CSS config file: tailwind.config.js
Created PostCSS config file: postcss.config.js

Open the tailwind.config.js file to verify. Y

module.exports = {
  content material: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
  darkMode: media,
  theme: {
    prolong: {},
  },
  variants: {
    prolong: {},
  },
  plugins: [],
}

Write the @tailwind directive for Tailwind CSS within the world.css file within the /types listing. 

By default, world.css is imported into the _app.js file.

@tailwind base;
@tailwind elements;
@tailwind utilities;

The setup for utilizing Tailwind CSS is now full. In the event you like, you possibly can take the next perform beneath to see that it really works in apply.

export default perform Dwelling() {
  return (
    <div>
      <h2 className="text-2xl font-bold text-gray-700 darkish:text-white hover:text-gray-600 darkish:hover:text-gray-200 hover:underline">
        Tailwind CSS in Subsequent.js
      </h2>
    </div>
  );
}

Customization with _document.js

In Subsequent, tags equivalent to Physique, Head, and Script are robotically set in your index.js file. And with _document.js you possibly can customise International settings for all of your pages/software.

Talking of frequent settings for all pages, there’s _app.js which used for structure settings. In _app.js, settings are mirrored solely within the physique tag, however in _document.js, modifications will be made to the HTML and Head tags. Additionally it is potential so as to add elements contained in the Physique tag in _document.js.


Let’s create a _document.js file within the /pages listing. 

Then, you possibly can take the perform beneath and place it in that file.

import Doc, { Html, Head, Major, NextScript } from 'subsequent/doc';

class MyDocument extends Doc {
  render() {
    return (
      <Html>
        <Head />
        <physique>
          <Major />
          <div id="portal"></div>
          <NextScript />
        </physique>
      </Html>
    );
  }
}

export default MyDocument;

/* this perform is a snippet from the official Subsequent.js docs */

We all know that the _document.js file customizes the HTML tag, however it’s possible you’ll be questioning what would occur if we eliminated the Major tag within the _document.js file. 

Let’s delete it and test.

In the event you delete the Major tag, the content material written within the index.js file won’t be displayed. From this, we will see that the content material of the index.js file is displayed within the Major tag. The Head tag and NextScript tag written in _document.js, not the Major tag, are required, so should you delete them, the web page won’t be displayed because of an error.

For the reason that _document.js file is processed on the server facet, it can’t be executed even when a click on occasion is about. As a substitute, if you wish to use React’s Portal function for issues like modal home windows, you possibly can add <div id=”portal”></div> earlier than the closing physique tag.

import Doc, { Html, Head, Major, NextScript } from 'subsequent/doc';

class MyDocument extends Doc {
  render() {
    return (
      <Html lang="ja">
        <Head />
        <physique>
          <Major />
          <div id="portal"></div>
          <NextScript />
        </physique>
      </Html>
    );
  }
}

export default MyDocument;

Wanting on the supply, the script is registered by the NextSciprt tag earlier than the closing tag of the physique tag, however the added div id=”portal” factor is beneath the <div id=”_next”></div> tag.

<physique>
    <div id="__next"></div>
    <div id="portal"></div>
</physique>

Font Settings

You may as well use the _document.js file if you wish to use a customized font from websites like Google Fonts.

First, search by way of Google Fonts to search out the font you need. My choice is Outfit, nevertheless it doesn’t matter. Click on on the font you need, choose the fashion and seize the main points.

Google Fonts – Outfit

Copy the <hyperlink> tag and place it instantly in your _document.js file. Like so:

import Doc, { Html, Head, Major, NextScript } from 'subsequent/doc';

class MyDocument extends Doc {
  render() {
    return (
      <Html>
        <Head>
          <hyperlink rel="preconnect" href="https://fonts.googleapis.com" />
          <hyperlink rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
          <hyperlink
            href="https://fonts.googleapis.com/css2?household=Outfit&show=swap"
            rel="stylesheet"
          />
        </Head>
        <physique>
          <Major />
          <NextScript />
        </physique>
      </Html>
    );
  }
}

export default MyDocument;

You possibly can then outline Outfit within the world.css file.

html,
physique {
  padding: 0;
  margin: 0;
  font-family: Outfit, -apple-system, BlinkMacSystemFont, Segoe UI,
    Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}

If world.css is just not imported in _app.js, the font won’t be utilized, so it is advisable be certain that world.css is imported.

Abstract

In the event you made it this far, congrats – try to be nicely in your option to having a common understanding of how Subsequent.js works, and now it’s time so that you can take all that data and work on a venture of your personal.

And lastly, this tutorial is actively being up to date and monitored to make sure that the directions offered are consistent with the most recent model of Subsequent and canopy any new options which may be launched to the framework in future releases.

In the event you loved this tutorial, share it with your folks!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments