映画詳細ページの作成
API
映画取得API
frontend/src/services/movies/getMovie.ts
import { ApiContext, Movie } from '@/types/data';
import { fetcher } from '@/utils';
const context: ApiContext = {
apiRootUrl: process.env.NEXT_PUBLIC_API_BASE_URL,
};
/**
* 映画取得API
* @param movieId - 映画ID
* @returns 映画
*/
const getMovie = async (movieId: number): Promise<{ movie: Movie }> => {
return await fetcher(`${context.apiRootUrl?.replace(/\/$/g, '')}/movies/${movieId}/`, {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
cache: 'no-store',
});
};
export default getMovie;
コンポーネント
映画詳細カードコンポーネント
frontend/src/app/components/movie/MovieCardDetail.tsx
import { Movie } from '@/types/data';
import Image from 'next/image';
import React from 'react';
type Props = {
movie: Movie;
};
const MovieCardDetail = (props: Props) => {
const img_url = '/img/dummy_poster.png';
return (
<>
<article key={props.movie.id}>
<div className="mx-4 my-4 flex">
<div className="flex-shrink-0 md:block">
<Image src={img_url} alt="" width={150} height={224} priority={true} />
</div>
<div className="ml-6">
<div>
<h3 className="text-3xl font-semibold text-gray-800">{props.movie.title}</h3>
</div>
<div className="my-2 flex">
<div className="mx-1 my-1 rounded bg-gray-200 px-1 py-0.5 text-sm text-gray-800">
{props.movie.year}
</div>
</div>
<div className="my-2 flex">
{props.movie.genres.map((genre) => (
<div
className="mx-1 rounded bg-blue-500 px-1 py-0.5 text-xs text-white"
key={genre}
>
{genre}
</div>
))}
</div>
</div>
</div>
</article>
</>
);
};
export default MovieCardDetail;
ページ
映画詳細ページ
frontend/src/app/movies/[id]/page.tsx
import MovieCardDetail from '@/app/components/movie/MovieCardDetail';
import getMovie from '@/services/movies/getMovie';
import connectUser from '@/services/users/connectUser';
const Movie = async ({ params }: { params: Promise<{ id: number }> }) => {
await connectUser();
const { id } = await params;
const movieId = id;
const { movie } = await getMovie(movieId);
return (
<>
<MovieCardDetail movie={movie} />
</>
);
};
export default Movie;
tsconfig.jsonの設定
frontend/tsconfig.json
{
...(略)...
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts", // <- 「,」を追加
".next/types/app/movies/[id]/page.tsx" // <- 追加
],
"exclude": ["node_modules"]
}
ブラウザで下記URLにアクセスすると、映画ID 1の詳細ページが表示されます。
映画リスト内の映画をクリックすることでも詳細ページが表示されます。
参考
- 【Next.js 15】動的ルーティング設定時に発生したエラーについて #AppRouter - Qiita
- 手島拓也,吉田健人,高林佳稀,『TypeScriptとReact/Next.jsでつくる 実践Webアプリケーション開発』,技術評論社,2022.
- 6.9.5 商品詳細ページ