Next.js 강의를 수강하던 도중 다음과 같은 에러가 발생했습니다.
Error: Route "/movies/[id]" used `params.id`. `params` should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis at MovieDetail (src/app/(movies)/movies/[id]/page.tsx:6:10)
강의 내용과 버전차이가 있어서 발생한 문제로 파악되어 공식문서를 참고했습니다.
주어진 오류는 params를 비동기적으로 처리해야 한다는 것을 의미합니다.
경고 발생 원인
코드 내에서 동적 렌더링을 사용하는 API에 접근할 때 발생합니다.
이는 Next.js 15부터 Dynamic APIs가 비동기적으로 변경되면서 발생하는 경고입니다.
동적 API의 종류?
- params 및 searchParams: 페이지, 레이아웃, 메타데이터 API 및 라우트 핸들러에 제공되는 props
- cookies(), draftMode(), headers(): next/headers에서 가져오는 함수
Next.js 15부터 이러한 API는 비동기적으로 처리됩니다. 이전 버전에서는 직접 접근이 가능했지만, 이제는 경고가 발생하고, 향후 버전에서는 직접 접근이 불가능해집니다.
코드 예시
function Page({ params }) {
// direct access of `params.id`.
return <p>ID: {params.id}</p>
}
해결 방법
- Codemod 사용: bash$ npx @next/codemod@canary next-async-request-api
- Codemod가 모든 경우를 처리할 수 없으므로, 일부 코드는 수동으로 조정해야 할 수도 있습니다.
- next-async-request-api codemod를 사용하여 많은 경우를 자동으로 수정할 수 있습니다.
- Server Component 또는 Route Handler:
async function Page({ params }) { // params.id에 비동기적으로 접근 const { id } = await params; return <p>ID: {id}</p>; }
- 경고가 Server (Route Handler 또는 Server Component)에서 발생한 경우, await 키워드를 사용하여 Dynamic API의 속성에 접근해야 합니다.
- Client Component:
'use client'; import * as React from 'react' function Page({ params }) { // params.id에 비동기적으로 접근 const { id } = React.use(params); return <p>ID: {id}</p>; }
- 경고가 동기적인 컴포넌트 (Client Component)에서 발생한 경우, React.use()를 사용하여 Promise를 풀어야 합니다.
해결 불가능한 경우
Codemod가 자동으로 마이그레이션할 수 없는 경우, @next-codemod-error 접두사가 붙은 주석이 코드에 추가됩니다. 주석에 제안된 작업에 따라 코드를 수정해야 합니다.
export function MyCookiesComponent() {
const c =
*/* @next-codemod-error Manually await this call and refactor the function to be async */*
cookies();
return c.get('name');
}
이 경우, cookies() 호출을 await하고, 함수를 async로 변경해야 합니다. 그런 다음, 해당 함수를 사용하는 부분을 적절히 await하도록 리팩터링해야 합니다.
Linter를 통한 강제 마이그레이션
Next.js는 개발 및 빌드 시 오류를 발생시켜 문제 해결을 강제합니다.
주석 접두사를 @next-codemod-error에서 @next-codemod-ignore로 변경하여 오류를 무시할 수 있습니다.
/* @next-codemod-error <suggested message> */
/* @next-codemod-ignore */
문제 해결 전후 비교
🙅 기존 코드
import { Suspense } from 'react';
import MovieVideos from '@/components/movie-video';
import MovieInfo from '@/components/movie-info';
export default async function MovieDetail({ params: { id } }: { params: { id: string } }) {
return (
<div>
<h3>Movie detail page</h3>
<Suspense fallback={<h1>Loading movie info</h1>}>
<MovieInfo id={id} />
</Suspense>
<Suspense fallback={<h1>Loading movie videos</h1>}>
<MovieVideos id={id} />
</Suspense>
</div>
);
}
✅ 문제를 해결한 코드
import { Suspense } from 'react';
import MovieVideos from '@/components/movie-video';
import MovieInfo from '@/components/movie-info';
export default async function MovieDetail({ params }: { params: { id: string } }) {
const { id } = await params; // id을 직접 받아서 사용합니다~
return (
<div>
<h3>Movie detail page</h3>
<Suspense fallback={<h1>Loading movie info</h1>}>
<MovieInfo id={id} />
</Suspense>
<Suspense fallback={<h1>Loading movie videos</h1>}>
<MovieVideos id={id} />
</Suspense>
</div>
);
}
기존에 파라미터로 id를 매개변수에 넣어주던 것을, 함수 내부로 직접 선언하여 받아오는 방식으로 변경하면 에러가 더 이상 나타나지 않습니다.
Ref.
해당 글은 Next.js 15.2.0 기준으로, 버전에 따라 차이가 있을 수 있습니다!
Dynamic APIs are Asynchronous
Learn more about why accessing certain APIs synchronously now warns.
nextjs.org