Next JS 컴포넌트 분리하기
Intro
- 본 내용은 강의 제공 사이트 유데미 Laith Harb 강사님의 "The Next.js 13 Bootcamp - The Complete Developer Guide" 강의를 듣고 정리하였습니다.
- https://www.udemy.com/course/the-nextjs-13-bootcamp-the-complete-developer-guide/
컴포넌트 분리
React
의 하나의 철칙인 컴포넌트 분리를 적용해봅시다. componets
폴더를 만듭니다.
// components/Header.tsx
"use client"
import { useRouter } from "next/navigation";
import { useState } from "react";
export default function Header() {
const router = useRouter();
const [location, setLocation] = useState("");
return (
<div className="h-64 bg-gradient-to-r from-[#0f1f47] to-[#5f6984] p-2">
<div className="text-center mt-10">
<h1 className="text-white text-5xl font-bold mb-2">
Find your table for any occasion
</h1>
{/* SEARCH BAR */}
<div className="text-left text-lg py-3 m-auto flex justify-center">
<input
className="rounded mr-3 p-2 w-[450px]"
type="text"
placeholder="State, city or town"
value={location}
onChange={(e) => setLocation(e.target.value)}
/>
<button className="rounded bg-red-600 px-9 py-2 text-white" onClick={() => {
if(location === "banana") return;
router.push("/search");
}}>
Let's go
</button>
</div>
{/* SEARCH BAR */}
</div>
</div>
)
}
위의 컴포넌트에서는 훅을 사용하므로 클라이언트 요소로 바꿔주어야 합니다. "use client"
를 상단에 입력합니다.
// page.tsx
import Header from './components/Header'
import NavBar from './components/NavBar'
import RestaurantCard from './components/RestaurantCard'
export default function Home() {
return (
<main className="bg-gray-100 min-h-screen w-screen">
<main className="max-w-screen-2xl m-auto bg-white">
<NavBar/>
<main>
<Header/>
<div className="py-3 px-36 mt-10 flex flex-wrap justify-center">
<RestaurantCard/>
</div>
</main>
</main>
</main>
)
}
SSR CSR
Client Side Rendering은 특정 페이지를 서버측에 요청합니다. 그런 다음 서버는 계속해서 렌더링할 HTML페이지를 제공합니다. 이 과정에서 클라이언트는 Javascript 번들 구문을 분석해 HTML을 렌더링하게 됩니다.
Server Side Rendering을 사용하는 경우 말그대로 서버측에서 HTML을 렌더링하여 클라이언트에게 보내기만 합니다. Next
에서는 이 과정 둘다 적용이 가능합니다.
Server Side Rendering의 경우 클라이언트가 구문을 분석할 필요가 없어 초기 로드가 훨씬 빨라집니다. 또한 SEO면에서도 서버에서 렌더링을 끝냈기 때문에 우월합니다.
이전에서 tsx
파일에 훅을 적용하기위해 "use client"
라고 명시했다면 클라이언트 사이드에서 렌더링을 진행하게 됩니다. 즉, default
는 Server Side Rendering입니다.
최종적으로 언제든지 혼용해 사용할 수 있으므로 특정 서버 구성 요소(Component
)는 클라이언트 구성 요소(Component
)를 렌더링(자식요소)하고, 특정 서버 구성 요소가 다른 서버 구성요소(자식요소)를 렌더링 할 수 있습니다.
하지만 클라이언트 구성 요소는 서버 구성 요소를 렌더링하지 못합니다. 클라이언트 구성 요소 클라이언트 구성 요소(자식요소)만 렌더링 할 수 있습니다.
그런데 밑에 그림을 보시면 클라이언트 요소에서 서버 구성 요소를 자식으로 가지기도 합니다. 실제로는 자식 요소로 전달되기만 할뿐, 서버측에서 렌더링됩니다.
정리하자면 다음과 같습니다.
layout.tsx
을 이용해 반복 컴포넌트 줄이기
루트 경로에 layout.tsx
의 경우 루트 레이아웃입니다. 즉, 각 페이지마다 공통으로 쓰이는 레이아웃입니다.
// layout.tsx
import NavBar from './components/NavBar'
import './globals.css'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
{/*
<head /> will contain the components returned by the nearest parent
head.tsx. Find out more at https://beta.nextjs.org/docs/api-reference/file-conventions/head
*/}
<head />
<body>
<main className="bg-gray-100 min-h-screen w-screen">
<main className="max-w-screen-2xl m-auto bg-white">
<NavBar/>
{children}
</main>
</main>
</body>
</html>
)
}
이 페이지에서는 모든 페이지에서 공통적으로 쓰이는 요소 Header
, Footer
등 반복되는 컴포넌트를 줄일 수 있죠. 또한 layout.tsx
파일은 루트 경로가 아닌 각 페이지별 경로에도 추가하여 해당 페이지의 공통 컴포넌트를 정리할 수도 있습니다.
// restaurant/[slug]/layout.tsx
import Header from "./components/Header";
export default function RestaurantLayout({
children,
// children은 타입이 React.ReactNode
}: {
children: React.ReactNode
}) {
return (
<main>
<Header/>
<div className="flex m-auto w-2/3 justify-between items-start 0 -mt-11">
{children}
</div>
</main>
)
}
head.tsx
를 이용해 메타 데이터 정리하기
layout.tsx
파일과 같이 루트 경로에 head.tsx
파일이 존재합니다.
// head.tsx
export default function Head() {
return (
<>
<title>Create Next App</title>
<meta content="width=device-width, initial-scale=1" name="viewport" />
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</>
)
}
head.tsx
도 마찬가지로 page 경로 마다 추가하여 사용할 수 있습니다.
public
리소스 디렉토리
public 디렉토리의 경로 보통 리소스 파일을 저장해둡니다. 리소스 파일은 /이름
과 같이 접근할 수 있습니다.