기본적인 페이지 구조
// /app/layout.tsx
import './globals.css';
import type { Metadata } from 'next';
import { Urbanist } from 'next/font/google';
import Footer from '@/components/Footer';
import NavBar from '@/components/NavBar';
const font = Urbanist({ subsets: ['latin'] });
export const metadata: Metadata = {
title: 'Store',
description: 'Store',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang='en'>
<body className={font.className}>
<NavBar />
{children}
<Footer />
</body>
</html>
);
}
NavBar에서 admin
의 카테고리 fetching
//actions/get-categories.ts
import { Category } from '@/types';
const URL = `${process.env.NEXT_PUBLIC_API_URL}/categories`;
const getCategories = async (): Promise<Category[]> => {
const res = await fetch(URL);
return res.json();
};
export default getCategories;
import Container from '@/components/ui/container';
import Link from 'next/link';
import MainNav from '@/components/MainNav';
import getCategories from '@/actions/get-categories';
// 캐시 하지 않겠다.
export const revalidate = 0;
export default async function NavBar() {
const categories = await getCategories();
return (
<div className='border-b'>
<Container>
<div className='relative px-4 sm:px-6 lg:px-8 flex h-16 items-center'>
<Link href='/' className='ml-4 flex lg:ml-0 gap-x-2'>
<p className='font-bold text-xl'>STORE</p>
</Link>
<MainNav data={categories} />
</div>
</Container>
</div>
);
}
MainNav는 카테고리를 받아서 Link 컴포넌트로 렌더링
export default function MainNav({ data }: MainNavProps) {
const pathname = usePathname();
const routes = data.map((route) => ({
href: `/category/${route.id}`,
label: route.name,
active: pathname === `/category/${route.id}`,
}));
return (
<nav className='mx-2 flex items-center space-x-4 lg:space-x-6'>
{routes.map((route) => (
<Link
key={route.href}
href={route.href}
className={cn(
'text-sm font-medium transition-colors hover:text-black',
route.active ? 'text-black' : 'text-neutral-500'
)}
>
{route.label}
</Link>
))}
</nav>
);
}