Next.js에서 다이나믹 라우팅(Dynamic Routing)은 동적으로 경로를 생성하고 처리하는 기능을 제공한다.
동적인 URL 경로에 따라 페이지를 렌더링하고 데이터를 가져올 수 있다.
다이나믹 라우팅은 주로 경로에 파라미터를 포함하여 사용되는데 파라미터는 URL경로의 일부로 사용된다.
파라미터는 [ ]를 써서 경로 패턴에 표시 되고
page폴더 내에서 파일 명에 []를 사용하여 생성한다.
예를 들어, /users/[userId].js
파일이 있다고 가정해봅시다. 이 파일은 /users/1
, /users/2
, /users/3
과 같은 경로로 접근할 때 사용
[userId]
는 사용자의 ID 값에 해당하는 동적인 파라미터.
Userspage의 각 사용자 목록에서 개별아이디에 따라 넘어가도록 링크를 해둠.
{users.map(user => {
return (
<>
<ul>
<li key={user.id}>
<Link href={`/users/${user.id}`}>
{user.name}
</Link>
</li>
</ul>
</>
)
})}
page.tsx 폴더 생성.
params의 타입을 지정해준다.
function UserPage(param: type){}의 형태이다.
{ params: { userId } }→ 얘가 params
Params → 얘가 type
datafetch 함수에 보낼거기 때문에 string으로 타입을 설정해준다.
type Params = {
params: {
userId: string
}
}
export default function UserPage({ params: { userId } }: Params) {
return (
<div>page</div>
)
}
이전에 users 데이터를 fetch 한 것 처럼 async / await사용!
UserPage에서 userId의 타입을 string으로 했기 때문에 여기서도 string 타입은 string
export default async function getUser(userId: string) {
const res = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)
if (!res.ok) throw new Error('실패했습니다.')
return res.json();
}
각 유저의 게시물도 가져올 것이기 때문에 lib 폴더에 posts를 fetch할 것을 하나 더 만들어줌
export default async function getUserPosts(userId: string) {
const res = await fetch(`https://jsonplaceholder.typicode.com/posts?userId=${userId}`)
if (!res.ok) throw new Error('실패했습니다.')
return res.json();
}
만들어둔 fetch 함수를 불러와주고
types.d.ts에서 Post의 타입을 지정해줌
type Post = {
"userId": number,
"id": number,
"title": string,
"body": string
}
import getUser from "@/lib/getUser"
import getUserPosts from "@/lib/getUserPosts"
import UserPosts from "./components/UserPosts";
import { Suspense } from "react";
export default async function UserPage({ params: { userId } }: Params) {
//단일 데이터를 받아올 때는 []없고 단일 데이터가 아니면 []
const userData: Promise<User> = getUser(userId);
const userPostsData: Promise<Post[]> = getUserPosts(userId);
const user = await userData;
//한번에 데이터를 받아올 때 all사용
// const [user, userPosts] = await Promise.all([userData, userPostsData])
return (
<>
<h2>{user.name}</h2>
<br />
//Suspense는 React의 Suspense 컴포넌트를 활용하여 데이터 로딩과 관련된 지연 처리를 수행하는 기능
<Suspense fallback={<h2>Loading...</h2>}>
//UserPosts컴포넌트로 게시물 보여줌
<UserPosts promise={userPostsData} />
</Suspense>
</>
)
}
Suspense는 React의 Suspense 컴포넌트를 활용하여 데이터 로딩과 관련된 지연 처리를 수행하는 기능
UserPosts 컴포넌트가 데이터를 로딩할 동안 fallback에 있는 내용을 보여준다.
components폴더를 만들고 UserPosts 컴포넌트를 만든다.
promise라는 이름으로 props를 보냈기 때문에
Props의 타입을 지정해준다.
type Props = {
//비동기 작업의 결과로 포스트 목록을 포함하는 Promise 객체
promise: Promise<Post[]>
}
export default async function UserPosts({ promise }: Props) {
//await promise는 비동기 작업이 완료될 때까지 실행을 일시 중지하고, 작업이 완료된 후에는 포스트 목록을 받아
const posts = await promise;
const content = posts.map(post => {
return (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.body}</p>
<br />
</article>
)
})
return content
}
이러면 user에 따라 게시물들이 잘 나옴.