๐ก NestJs๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ ๋๋งํ๋ ๋ฐฉ์
๋ ๋(render) ๋? : nextjs๊ฐ ์ฐ๋ฆฌ์ react component๋ฅผ ๊ฐ์ ธ์์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ดํดํ ์ ์๋ html๋ก ๋ณํํ๋ ๊ณผ์ ์ ์๋ฏธํจ
๐ก ํ๋ฒํ react๊ฐ ๋ ๋๋๋ ๋ฐฉ์์ Client Side Rendering : ์ฆ ๋ธ๋ผ์ฐ์ ๊ฐ ์ง์ ๋ ๋๋ง์ ํ๋ ๊ณผ์ ,
ํ๋ฒํ react๋ง์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ฑํ๋ฉด ๊ทธ๊ฒ์ Client Side Application์ด ๋จ.
CSR ํน์ง
- ์ ์ ๊ฐ ํ์ด์ง์ ๋์ฐฉํ ์์ ์ ํ์ด์ง๋ ๋น ํ๋ฉด์. ๊ทธ ์ดํ ๋ธ๋ผ์ฐ์ ๊ฐ ๋ชจ๋ JSํ์ผ์ ๋ค์ด๋ก๋ํ๊ณ ๋ ํ์์ผ UI๊ฐ ๊ทธ๋ ค์ง๊ธฐ ์์ํจ. (์ฆ CSR์์ UI๋ ๋ธ๋ผ์ฐ์ ์ JS์์ง์ ์ํด ๊ทธ๋ ค์ง๊ฒ ๋๋ค.)
- ๊ทธ๋์ ์๋ก๊ณ ์นจ๋ฑ ํ์ด์ง๋ฅผ ๋ค์ ๊ทธ๋ฆฌ๋ ๊ฒฝ์ฐ๊ฐ ์๊ธฐ๋ฉด, UI๊ฐ ์ญ์ ๋ ์ผ์์ ์ผ๋ก ํ๋ฉด์ ๋ด์ฉ์ด ์ญ์ ๋จ.
- SEO (๊ฒ์์์ง์ต์ ํ)๋ฅผ ํ์ฉํ๊ธฐ ์ํด์๋ google์๊ฒ ๋น ํ์ด์ง๋ฅผ ๋ณด์ฌ์ฃผ์ง ์๋ ๊ฒ์ด ์ข์ง๋ง (Google์ ํ์ด์ง์ HTML์ ๋ณด๊ธฐ๋๋ฌธ) ๊ฒ์ ์์ง์ด ๋ณด๊ฒ ๋๋ ์น์ฌ์ดํธ๋ ๋น์ด์๊ฒ ๋จ.
๐ก Nestjs์์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ด์ง๋ฅผ ๋ ๋ํ๋ ๋ฐฉ์์ Server Side Rendering : ํ์ด์ง์ ์์ค์ฝ๋๋ฅผ ๋ณด๊ฒ ๋๋ฉด ๋ฆฌ์กํธ์๋ ๋ค๋ฅด๊ฒ ํ์ด์ง์ ๋ด์ฉ๋ค์ด ๋ชจ๋ ์ค์ ๋ก ๋ธ๋ผ์ฐ์ ์ฝ๋์ ์์. ๊ทธ๋ฌ๋ฏ๋ก ๋ธ๋ผ์ฐ์ ๋ HTML์ ํ๋ฉด์ ๊ทธ๋ฆฌ๊ธฐ ์ํด JS๊ฐ ๋ก๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆด ํ์๊ฐ ์๊ฒ ๋จ.
NestJs์์ ๋ชจ๋ ์ปดํฌ๋ํธ๋ค์ ์ฐ์ ์ ์ผ๋ก Server Side Rendering ๋๊ฒ ๋จ.
SSR ํน์ง
- UI๋ฅผ ๋น๋ํ๋๋ฐ React๋ฅผ ์ธ ํ์๊ฐ ์์. ๋ชจ๋ ์ปดํฌ๋ํธ์ ํ์ด์ง๋ค์ ์ฐ์ ๋ฐฑ์๋์์ ๋ฏธ๋ฆฌ ๋ ๋๋์ด์ง.
- ์ด๋ ๊ฒ ๋๋ฉด ์ฌ์ฉ์๋ค์ด ํ์ด์ง์ ์ ๊ทผํด์ ๋ฐ๋ก UI๋ฅผ ๋ณผ ์ ์๋ค๋ผ๋ ์ฅ์ ์ด ์์.
๐ก Hydration : Hydrate๋ ๋ฐฑ์๋์์ ๋ ๋๋ง๋ ๋จ์ HTML๊ณผ ๋ฒ๋ค๋ง๋ JS๋ฅผ ํด๋ผ์ด์ธํธ๋ก ๋ณด๋ธ ๋ค, ํด๋ผ์ด์ธํธ์ธก์์ ๋จ์ HTML์ ๋ฆฌ์กํธ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ์ด๊ธฐํํ๋ ๊ณผ์ ์ ์๋ฏธ.
Link ์ปดํฌ๋ํธ ์์:
1. Link์ปดํฌ๋ํธ๋ฅผ ๋ฐฑ์๋์์๋ ๋จ์ํ anchorํ๊ทธ๋ก ๋ณํํด ๋๊ธฐ์, ๋ฐฑ์๋์ ๋ ๋๋ง ๋ ์๊ฐ์ html์ anchorํ๊ทธ๋ก UI๋ฅผ ๊ทธ๋ฆฌ๊ฒ ๋จ.
2. ์ดํ, ์ ์ ๊ฐ ํ์ด์ง์ ๋๋ฌํ ์ดํ์๋ ๋ฆฌ์กํธ, ์ปดํฌ๋ํธ๊ฐ ๋ก๋๋๋ฉฐ ์ฐ๋ฆฌ ์ ํ๋ฆฌ์ผ์ด์ ์ React App์ด ๋จ.
3. ์ ํ๋ฆฌํค์ด์ ์ interactiveํด์ง๊ณ ๊ทธ๋ก ์ธํด Link ์ปดํฌ๋ํธ๋ฅผ ํตํด ์๋ก๊ณ ์นจ ์์ด ํ์ด์ง๋ฅผ ์ด๋ํ ์ ์๋ Client Side Navigation์ ํ ์ ์๊ฒ ๋จ.
๐ฃ๏ธ ๊ทธ๋ฌ๋ Hydration ์ ๋ชจ๋ ์ปดํฌ๋ํธ์ ๋ฐ์ํ์ง ์์.
๋ชจ๋ ์ปดํฌ๋ํธ๋ค์ server side์์ ๋จผ์ ๋ ๋๋์ง๋ง ๊ทธ ์ค client์์ interactiveํ๊ฒ ๋ง๋ค์ด์ง ์ปดํฌ๋ํธ๋ค์ ์ค์ง use client ์ง์์ด๋ฅผ ๋งจ ์์ ๊ฐ๊ณ ์๋ ์ปดํฌ๋ํธ ๋ค ๋ฟ์.
- use client : use client๋ ๋ฐฑ์๋์์ ๋ ๋๋๊ณ ํ๋ก ํธ์๋์์ Hydrate๋จ์ ์๋ฏธ ์ค์ง client์์๋ง ๋ ๋๋๋ค๋ ๊ฒ์ ์๋ฏธํ๋ ๊ฒ์ด ์๋.
- ํ๋ ์์ํฌ์๊ฒ ์ด๋ค ์ปดํฌ๋ํธ๊ฐ interactiveํด์ง๊ณ ์ด๋ค ์ปดํฌ๋ํธ๋ ๋จ์ํ html์์ ๋ฏธ๋ฆฌ ์๋ ค์ฃผ๋ฉด ์ด๋ ์ฌ์ฉ์๊ฐ ๋ค์ด๋ก๋๋ฐ์ javascript ์์ด ์ ์ด์ง์ ์๋ฏธํจ.
- client component : use client ํค์๋๋ฅผ ์ต์๋ถ์ ์ ์ธํ ์ปดํฌ๋ํธ๋ค
- server component์์ client component๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๊ฐ๋ฅํจ, client component์์ server component๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํจ.
- client component์์ ํธ์ถ๋๋ ์ปดํฌ๋ํธ๋ค์ client component๊ฐ ๋จ. (2024.2์ ๊ธฐ์ค)
// components/movie-video.tsx "use client"; import styles from "../styles/movie-videos.module.css"; import { API_URL } from "../app/(home)/page"; async function getVideos(id: string) { const response = await fetch(${API_URL}/${id}/videos); return response.json(); } export default async function MovieVideos({ id }: { id: string }) { const videos = await getVideos(id); return ( <div className={styles.container}> {videos.map((video) => ( <iframe key={video.id} src={https://youtube.com/embed/${video.key}} title={video.name} /> ))} </div> ); }์๋ฌ : Error: ร You are attempting to export "metadata" from a component marked with "use client", which is disallowed. Either remove the export, or the "use client" directive.
(์๋ฌ ๋ฉ์ธ์ง ์ ๋ฌธ) Error: ร You are attempting to export "metadata" from a component marked with "use client", which is disallowed. Either remove the export, or the "use client" directive. Read more: https://nextjs.org/ โ docs/getting-started/react-essentials#the-use-client-directive โ โ โญโ[/Users/chaeyeongmin/Desktop/JavaScript/Next.js/nextjs14/app/(home)/page.tsx:2:1] 2 โ import Movie from "../../components/movie"; 3 โ import styles from "../../styles/home.module.css"; 4 โ 5 โ export const metadata: Metadata = { ยท โโโโโโโโ 6 โ title: "Home", 7 โ }; โฐโโโโ Import trace for requested module: ./app/(home)/page.tsx ./components/movie-videos.tsx
import { Metadata } from "next"; import Movie from "../../components/movie"; import styles from "../../styles/home.module.css"; export const metadata: Metadata = { title: "Home", }; export const API_URL = "https://nomad-movies.nomadcoders.workers.dev/movies"; async function getMovies() { const response = await fetch(API_URL); const json = await response.json(); return json; } export default async function HomePage() { const movies = await getMovies(); return ( <div className={styles.container}> {movies.map((movie) => ( <Movie key={movie.id} id={movie.id} poster_path={movie.poster_path} title={movie.title} /> ))} </div> ); }
๐ฃ๏ธ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ฝ์ด๋ณด๋, ์ง์์ ์ผ๋ก metadata๋ฅผ exportํ๋ ํ์๋ฅผ ์ง์ ํ๊ณ ์์ด์ ๋๋ metadata๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์๋ชป๋ ์ค ์์๋ค. ๊ทธ๋ฌ๋ ์์ ๋ ํ์ผ์์ metadata๋ ์ ํ ์ฐ๊ด์ด ์์๊ณ , ๊ฒฐ๊ตญ ๋ฌธ์ ์ ์์ธ์ 'use client' ์ง์์ด์ ํน์ฑ์ ์์๋ค. 'use client' ์ง์์ด๊ฐ ๋ถ์ ์ปดํฌ๋ํธ์์๋ ์ด๋ ํ ๋ณ์๋ exportํ ์ ์๋ ๊ฒ์ด ์์น์ด๊ธฐ ๋๋ฌธ์, ์ด๋ฅผ ์๋ฐํ๋ ๊ฒ์ด ๋ฌธ์ ์๋ค. ์ด๋ฌํ ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ ๋๋, API_URL์ ๊ฐ๊ฐ์ ์ปดํฌ๋ํธ์์ ๋ฐ๋ก ์ ์ธํจ์ผ๋ก์จ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์๋ค.
๐ก ์ค๋ฅ ํด๊ฒฐ
- ๋ค์๊ณผ ๊ฐ์ด import๋ก ์ฐธ์กฐํด์ค๋ API_URL์ ํด๋น ํ์ผ์์์ ๋ถ๋ฌ์ฃผ์๋ค.
"use client"; import styles from "../styles/movie-videos.module.css"; async function getVideos(id: string) { const API_URL = "https://nomad-movies.nomadcoders.workers.dev/movies"; const response = await fetch(`${API_URL}/${id}/videos`); return response.json(); } export default async function MovieVideos({ id }: { id: string }) { const videos = await getVideos(id); return ( <div className={styles.container}> {videos.map((video) => ( <iframe key={video.id} src={`https://youtube.com/embed/${video.key}`} title={video.name} </iframe> ))} </div> ); }