はじめに
本記事は、以下のNEXTJSのチュートリアルの内容をまとめたものである。
目次
- 事前準備
- ルーティングについて
- 全ページ表示させるコンポーネントの配置先
- API呼び出しの方法について
- Server Side Renderingの特徴
- どちらのコンポーネントで実装するか
事前準備
プロジェクトの作成
$ npm create next-app
以下で実行できることを確認
$ npm run dev
ルーティングについて
基本形
src/appフォルダ配下に任意の名称のフォルダを作成し、そのファイル名をpage.tsxとする
これだけで、/フォルダ名 のページにルーティングできるようになる。
/about というリソースを作成する場合は以下のようにする。
export default function About(){
return (
<div><h1> This is about page.</h1></div>
);
ネストしたroute
export default function AboutUs(){
return (
<div><h1> This is about us page.</h1></div>
);
dynamic route
export default function AboutWithId({ params }: any) {
return (
<div>
<h1> This is the about page with ID: {params.id} </h1>
</div>
);
}
全ページ共通で表示させるコンポーネントの配置
- Navbar
- Footer
など
Navbarをつけたい場合
import Link from "next/link";
export default function Navbar() {
return (
<div>
<Link href="/about"> About </Link>
<Link href="/about/us"> About Us</Link>
</div>
);
}
デフォルトで作成されている以下でrouteが管理されている。
{children}が、それぞれのpageの中身なので、その上にNavbarを入れればいい。
import "./globals.css";
import { Inter } from "next/font/google";
+ import Navbar from "./components/navbar";
const inter = Inter({ subsets: ["latin"] });
export const metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>
+ <Navbar />
{children}
</body>
</html>
);
}
API呼び出しの方法について
api呼び出し(x1)
const getPostsData = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
return res.json();
};
export default async function ListOfPosts() {
const posts = await getPostsData();
return (
<div>
{posts.map((post: any) => {
return <p> {post.title} </p>;
})}
</div>
);
}
api呼び出し(x2)
const getPostsData = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
return res.json();
};
+ const getUsersData = async () => {
+ const res = await fetch("https://jsonplaceholder.typicode.com/users");
+ return res.json();
+ };
export default async function ListOfPosts() {
- const posts = await getPostsData();
+ const [posts, usres] = await Promise.all([getPostsData(), getUsersData()]);
return (
<div>
{posts.map((post: any) => {
return <p> {post.title} </p>;
})}
+ {usres.map((user: any) => {
+ return <p> {user.name}</p>;
+ })}
</div>
);
}
Server Side Renderingはスタティックである
サーバーコンポーネントは、ブラウザのイベントやuseState hooksなどを使用できない。
また、基本的に最初のロード時にキャッシュされるため、中の要素はスタティックになる。
キャッシュの設定(時間設定なし)
リロード時に毎回APIを呼び出しフェッチしたい場合
import Image from "next/image";
const getPostsData = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
return res.json();
};
const getUsersData = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
return res.json();
};
const getDogData = async () => {
- const res = await fetch("https://dog.ceo/api/breeds/image/random");
+ const res = await fetch("https://dog.ceo/api/breeds/image/random", {
+ cache: "no-store",
+ });
return res.json();
};
export default async function ListOfPosts() {
const [posts, usres, dog] = await Promise.all([
getPostsData(),
getUsersData(),
getDogData(),
]);
return (
<div>
<Image src={dog.message} alt="dog" width={300} height={300} />
{posts.map((post: any) => {
return <p> {post.title} </p>;
})}
{usres.map((user: any) => {
return <p> {user.name}</p>;
})}
</div>
);
}
キャッシュの設定(時間設定あり)
指定秒数以上開けてリフレッシュされた場合に再取得したい場合
※以下例だと3秒以上開けた後ににリフレッシュした場合再フェッチされる
const getDogData = async () => {
const res = await fetch("https://dog.ceo/api/breeds/image/random", {
next: {
revalidate: 3,
},
});
return res.json();
};
他のウェブサイトやapiから画像を取得して表示させるためには、以下に取得を許可するドメインを設定する必要がある。
/** @type {import('next').NextConfig} */
const nextConfig = {
+ images: {
+ domains: ["images.dog.ceo"],
+ },
};
module.exports = nextConfig;
page以外の要素
error
サーバエラー発生時にクライアントにエラーを表示させたい場合に使用
※クライアント側のコンポーネントである必要があるため、"use client"が必要。
+ "use client";
export default function Error() {
return <div> There was an error loading the data.</div>;
}
loading
ページ読み込みの際に、「Loading...」のような表示をさせたい場合に使用
export default function Loading(){
return <div> Loading...</div>;
}
目的の違い
- クライアントコンポーネント
- ユーザと実際のクライアント(ブラウザ)の間を取り持つ。そのため、ブラウザイベントや、React Hooks(ブラウザのステートなど)を管理する。
- サーバーコンポーネント
- コンポーネントをサーバにレンダリングすることで、クライアントに送信しロードするjavascriptの量を減らすことができる。