page.js 파일
을 만들어서 공개적으로 접근 가능한 URL 경로를 만든다.서버 컴포넌트로 동작
한다.(성능 최적화 적용 가능) use client
"로 정의하면 된다.파일명(.js, jsx, .tsx) | 설명 |
---|---|
layout | 세그먼트와 그 자식들에 대한 공유하는 UI. 레이아웃 파일 |
page | 라우트의 고유한 UI(페이지)를 만들고 공개적으로 접근 가능하게 만드는 파일 |
loading | 세그먼트와 그 자식들에 대한 로딩 UI |
not-found | 세그먼트와 그 자식들에 대한 404 UI |
error/global-error | 세그먼트와 그 자식들에 대한 에러 UI. 글로벌 에러 UI |
route | 서버 측 API 엔드포인트(기존 pages의 api 폴더 역할) |
template | 커스텀 된(리렌더링) 레이아웃 UI(상태유지X) |
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
그렇다면 이제 제 프로젝트를 app router로 마이그레이션 해보겠습니다!
> yarn add next@latest
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<GoogleAnalytics GA_TRACKING_ID={process.env.NEXT_PUBLIC_GA_ID} />
<NextProvider>
<NextLayout>{children}</NextLayout>
</NextProvider>
</body>
</html>
);
}
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Hole in the wall",
description: "Next.js 13 로컬 맛집 앱",
};
// 기존 getServersideProps로 하던 패칭 방법
export async function getServerSideProps() {
const stores = await axios(`${process.env.NEXT_PUBLIC_API_URL}/api/stores`);
return {
props: { stores: stores.data },
};
}
⬇⬇⬇ ⬇⬇⬇ ⬇⬇⬇ ⬇⬇⬇ ⬇⬇⬇
// fetch api를 사용한 패칭 방법
// Home 내부에서 호출
const stores: StoreType[] = await getData();
async function getData() {
try {
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/stores`, {
cache: "no-store",
});
if (!res.ok) {
throw new Error("Failed to fetch data");
}
return res.json();
} catch (e) {
console.log(e);
}
}
// Markers.tsx
"use client";
import { currentStoreState, locationState, mapState } from "@/atom";
import { StoreType } from "@/interface";
import { useCallback, useEffect } from "react";
import { useSetRecoilState, useRecoilValue, useRecoilState } from "recoil";
useRouter()
, usePathname()
, useSearchParams()
변경'use client'
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
export default function ExampleClientComponent() {
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
// ...
}
// 기존의 useRouter를 사용해 url로 쿼리를 받음.
const router = useRouter();
const { page = "1" }: any = router.query;
// 새로운 useSearchParams 훅으로 parameters를 받음.
const searchParams = useSearchParams();
const page: any = searchParams?.get("page") || "1";
"use client";
export default function GlobalError({
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<html>
<body>
<div>
다시 시도해주세요.
<button
onClick={() => reset()}>
Try again
</button>
</div>
</body>
</html>
);
}
/app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth"
const handler = NextAuth({
...
})
export { handler as GET, handler as POST }
💥 해당 과정 중 생긴 오류
// 기존의 POST 메서드
import type { NextApiRequest, NextApiResponse } from "next";
import { StoreApiResponse, StoreType } from "@/interface";
import prisma from "@/db";
import axios from "axios";
import { getServerSession } from "next-auth";
import { authOptions } from "./auth/[...nextauth]";
interface Responsetype {
page?: string;
limit?: string;
q?: string;
district?: string;
id?: string;
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<StoreApiResponse | StoreType[] | StoreType | null>
) {
const { page = "", limit = "", q, district, id }: Responsetype = req.query;
const session = await getServerSession(req, res, authOptions);
if (req.method === "POST") {
const formData = req.body;
const headers = {
Authorization: `KakaoAK ${process.env.KAKAO_CLIENT_ID}`,
};
...
return res.status(200).json(result);
⬇⬇⬇ ⬇⬇⬇ ⬇⬇⬇ ⬇⬇⬇ ⬇⬇⬇
// NextResponse로 변경한 POST 메서드
import { NextResponse } from "next/server";
import prisma from "@/db";
import axios from "axios";
import { getServerSession } from "next-auth";
import { authOptions } from "@/app/utils/authOptions";
export async function POST(req: Request) {
// 데이터 생성을 처리한다.
const formData = await req.json();
const headers = {
Authorization: `KakaoAK ${process.env.KAKAO_CLIENT_ID}`,
};
...
return NextResponse.json(result, { status: 200 });
}
💡