1. 概要
前回はDynamic Routesの使い方についてでした。今回はSuspenseの使い方についてです。
<Suspense>
works by wrapping a component that performs an asynchronous action (e.g. fetch data), showing fallback UI (e.g. skeleton, spinner) while it’s happening, and then swapping in your component once the action completes.Routing: Loading UI and Streaming | Next.js (nextjs.org)
<Suspense>
は、非同期アクション(例:データ取得)を実行するコンポーネントをラップし、実行中はフォールバックUI(例:スケルトン、スピナー)を表示し、アクションが完了したらコンポーネントを入れ替えます。
対象としては開発を1年程やってて自分で最初から開発してみたい方になります。そのため細かい用語などの説明はしません。
2. nodeのインストール
こちらを参考
3. プロジェクトを作成
こちらを参考
4. 必要なライブラリをインストール
こちらを参考
5. ソースコード
※前回より差分のみを記載
5-1-1. next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "images.dog.ceo",
port: "",
pathname: "/breeds/**",
},
],
},
};
module.exports = nextConfig;
5-1-2. src/app/nextjs/nextjs03/loading.tsx
const Loading = () => {
return <p>Loading...</p>;
};
export default Loading;
5-1-3. src/app/nextjs/nextjs03/get-image.tsx
"use client";
import Image from "next/image";
const imageLoader = ({
src,
width,
quality,
}: {
src: string;
width: number;
quality?: number;
}) => {
return `${src}?w=${width}&q=${quality || 75}`;
};
const GetImage = ({ src }: { src: string }) => {
return (
<Image loader={imageLoader} src={src} alt="Dogs" width={500} height={500} />
);
};
export default GetImage;
5-1-4. src/app/nextjs/nextjs03/fetch-image.tsx
import GetImage from "./get-image";
const FetchImage = async () => {
const src = await getData();
return <GetImage src={src} />;
};
const getData = async () => {
const response = await fetch("https://dog.ceo/api/breeds/image/random", {
cache: "no-store",
});
if (!response.ok) {
throw new Error("Failed to fetch data");
}
const data = await response.json();
return data.message;
};
export default FetchImage;
5-1-5. src/app/nextjs/nextjs03/page.module.scss
.component {
color: blue;
& ul {
margin-left: 20px;
& li {
list-style: disc;
}
}
}
5-1-6. src/app/nextjs/nextjs03/page.tsx
import { Suspense } from "react";
import GoBack from "@/lib/components/go-back";
import scss from "./page.module.scss";
import Loading from "./loading";
import FetchImage from "./fetch-image";
const Nextjs03 = () => {
return (
<div className={scss.component}>
<GoBack />
<br />
<br />
<ul>
<li>Loading UI and Streaming</li>
<ul>
<li>Suspense</li>
<ul>
<li>
<Suspense fallback={<Loading />}>
<FetchImage />
</Suspense>
</li>
</ul>
</ul>
</ul>
<br />
</div>
);
};
export default Nextjs03;
5-1-7. src/app/nextjs/page.module.scss
.components {
color: blue;
& ul {
margin-left: 20px;
& li {
list-style: disc;
}
}
}
5-1-8. src/app/nextjs/page.tsx
"use client";
import React from "react";
import { Link } from "@mui/material";
import scss from "./page.module.scss";
const Nextjs = () => {
return (
<div className={scss.components}>
<ul>
<li>
<Link href="/nextjs/nextjs01" underline="hover">
Nextjs01
</Link>
</li>
<li>
<Link href="/nextjs/nextjs02" underline="hover">
Nextjs02
</Link>
</li>
<li>
<Link href="/nextjs/nextjs03" underline="hover">
Nextjs03
</Link>
</li>
</ul>
</div>
);
};
export default Nextjs;
6. サーバーを起動
npm run dev
7. ブラウザで確認
- http://localhost:3000
8. ディレクトリの構造
.
├── README.md
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ ├── js
│ │ └── script.js
│ ├── next.svg
│ └── vercel.svg
├── src
│ ├── app
│ │ ├── components
│ │ │ ├── component01
│ │ │ │ ├── page.module.scss
│ │ │ │ └── page.tsx
│ │ │ ├── component02
│ │ │ │ ├── page.module.scss
│ │ │ │ └── page.tsx
│ │ │ ├── component03
│ │ │ │ ├── page.module.scss
│ │ │ │ └── page.tsx
│ │ │ ├── component04
│ │ │ │ ├── checkbox-demo.tsx
│ │ │ │ ├── page.module.scss
│ │ │ │ ├── page.tsx
│ │ │ │ ├── radio-demo.tsx
│ │ │ │ └── select-demo.tsx
│ │ │ ├── page.module.scss
│ │ │ └── page.tsx
│ │ ├── events
│ │ │ ├── event01
│ │ │ │ ├── page.module.scss
│ │ │ │ └── page.tsx
│ │ │ ├── page.module.scss
│ │ │ └── page.tsx
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── globals.scss
│ │ ├── hooks
│ │ │ ├── hook01
│ │ │ │ ├── page.module.scss
│ │ │ │ └── page.tsx
│ │ │ ├── hook02
│ │ │ │ ├── page.module.scss
│ │ │ │ └── page.tsx
│ │ │ ├── hook03
│ │ │ │ ├── child.tsx
│ │ │ │ ├── counter-provider.tsx
│ │ │ │ ├── grandchild.tsx
│ │ │ │ ├── myself.tsx
│ │ │ │ ├── page.module.scss
│ │ │ │ └── page.tsx
│ │ │ ├── hook04
│ │ │ │ ├── page.module.scss
│ │ │ │ └── page.tsx
│ │ │ ├── hook05
│ │ │ │ ├── child.tsx
│ │ │ │ ├── counter-provider.tsx
│ │ │ │ ├── grandchild.tsx
│ │ │ │ ├── myself.tsx
│ │ │ │ ├── page.module.scss
│ │ │ │ └── page.tsx
│ │ │ ├── hook06
│ │ │ │ ├── child.tsx
│ │ │ │ ├── page.module.scss
│ │ │ │ ├── page.tsx
│ │ │ │ ├── play-provider.tsx
│ │ │ │ ├── text-box.tsx
│ │ │ │ └── video-player.tsx
│ │ │ ├── page.module.scss
│ │ │ └── page.tsx
│ │ ├── layout.module.scss
│ │ ├── layout.tsx
│ │ ├── nextjs
│ │ │ ├── nextjs01
│ │ │ │ ├── child
│ │ │ │ │ ├── client-page.tsx
│ │ │ │ │ ├── metadata.ts
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── page.module.scss
│ │ │ │ └── page.tsx
│ │ │ ├── nextjs02
│ │ │ │ ├── [...slug]
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── page.module.scss
│ │ │ │ ├── page.tsx
│ │ │ │ └── shop
│ │ │ │ └── [id]
│ │ │ │ └── page.tsx
│ │ │ ├── nextjs03
│ │ │ │ ├── fetch-image.tsx
│ │ │ │ ├── get-image.tsx
│ │ │ │ ├── loading.tsx
│ │ │ │ ├── page.module.scss
│ │ │ │ └── page.tsx
│ │ │ ├── page.module.scss
│ │ │ └── page.tsx
│ │ ├── page.module.scss
│ │ ├── page.tsx
│ │ └── redux
│ │ ├── page.module.scss
│ │ ├── page.tsx
│ │ ├── redux01
│ │ │ ├── child.tsx
│ │ │ ├── counter-slice.ts
│ │ │ ├── grandchild.tsx
│ │ │ ├── hooks.ts
│ │ │ ├── myself.tsx
│ │ │ ├── page.module.scss
│ │ │ ├── page.tsx
│ │ │ └── store.ts
│ │ └── redux02
│ │ ├── child.tsx
│ │ ├── hooks.ts
│ │ ├── image-box.tsx
│ │ ├── image-slice.ts
│ │ ├── page.module.scss
│ │ ├── page.tsx
│ │ ├── store.ts
│ │ ├── text-box.tsx
│ │ └── text-slice.ts
│ ├── lib
│ │ ├── common
│ │ │ ├── definitions.ts
│ │ │ └── sidebar-links.tsx
│ │ ├── components
│ │ │ ├── alert-snackbar.tsx
│ │ │ ├── go-back.tsx
│ │ │ └── spacer.tsx
│ │ ├── footer.tsx
│ │ ├── header.tsx
│ │ ├── sidebar.tsx
│ │ └── utils
│ │ └── util.ts
│ └── scss
│ └── common
│ ├── _index.scss
│ ├── _mixin.scss
│ ├── _mq.scss
│ └── _variables.scss
├── tailwind.config.ts
└── tsconfig.json
35 directories, 109 files
9. 備考
今回はSuspenseの使い方についてでした。
10. 参考
- Docs | Next.js (nextjs.org)
- Quick Start – React
- Getting Started with Redux | Redux
- Getting Started with React Redux | React Redux (react-redux.js.org)
- Material UI: React components based on Material Design (mui.com)
投稿者プロフィール
-
開発好きなシステムエンジニアです。
卓球にハマってます。