[ Nextjs 01 ] 프로젝트시작하기
[ 프로젝트 시작하기 ]
npx create-next-app@latest

- typescript 를 사용한다고 세팅할경우 위와같이 설치된다.
= react-dom 의 경우 dom 객체를 랜더링해주는 의존성이다.
[ 프로젝트 구조 ]
├── package.json
├── public
│ ├── next.svg
│ └── vercel.svg
├── src
│ └── app
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx
│ ├── page.module.css
│ └── page.tsx
layout.tsx, page.tsx 파일이 /src/app 디렉토리밑에 자동으로 생성된다.
- app 디렉토리의 명칭을 변경해서는 안된다.
- page.tsx 파일은 기본 페이지이다. 파일명을 바꾸면 랜더링이안된다.
[ layout.tsx 설명 ]
- default 함수 하나만 export. 해야한다.
[ Routing 방식 ]
과거에는 각 Component 에 라우팅을 지정되는 방식으로 구성되었다. ( react-router 의 라우팅 방식 )
/ → <Home />
/about-us → <AboutUs/>
/movies/:id → <Movie />
버전 : Nextjs 14.2.3.
/src/app 디렉토리밑에 폴더를 생성하고 page.tsx 를 생성하면, 라우팅은 자동으로 세팅된다.
단, page.tsx만 url에 포함되지 다른 파일과 폴더를 생성한다고 세팅되지않는다.


팁
- not found page 의 경우 app 디렉토리 밑에 not-found.tsx 파일을 생성하면된다. ( 단, 파일명이 중요한것이지 함수명은 아무거나 세팅가능 )
[SSR vs CSR]
react 는 client side rendering 방식, 브라우저에서 페이지를 표현한다. 브라우저의리소스를 사용한다.
- 페이지검사시 소스코드가없다.
- JavaScript파일을 다운로드하고 실행되어야 페이지가 랜더링된다. ( 랜더링시간 )
- 자바스크립트를 꺼놓은 사용자라면 랜더링되지않는다.
Nextjs는 server side rendering 을 기본으로한다.
- Hydration : 단순html을 React Component로 변환하는과정.
<Link…> 자체는 Javascript 가 켜져있다면 react 를 rendering 해서작동하고, 페이지가 깜빡임없이 SinglePage Application 으로 작동한다. 꺼지면 anchor로 작동하여 href로 작동함(새로고침 작동)
[“use client”]
nextjs 에서는 기본적으로 모든 component를 server side rendering 한다 하지만…
**client에서 hydration 하는 컴포넌트를 지정할 수 있다.
이렇게 지정하는이유는 서버사이드 랜더링할때 사용자가 불필요한 javascript를 다운받고 실행하는것을 방지할 수 있다. Nextjs 를 사용하는 이유 🔥
*그렇다고 use client가 오직 클라이언트에서만 랜더링된다는 뜻은 아니고 작은 javascript로 만들어서 일부 클라이언트에서 랜더링한다는 뜻이다.
팁
server component에서는 api 키를 넣어도된다! 🔥 서버쪽에서만 랜더링되기때문.
[ Layout ]
공통레이아웃을 작성할수있고
about-us/company/sales/page.tsx 파일을 만들어도
about-us 밑에 별도의 layout.tsx 파일이 있으면, 모두 하위파일에 적용된다.
*팁 Grouping 할수있다

괄호 안에 있는경우, url을 별도생성하지않는다.
[Metadata]
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Linker Blog | Company",
description: "Linker App Company page",
};
export default function Company(){
return(<h1>Company</h1>)
}
- Layout.js 에도 똑같이 metadata가 있지만, 병합되는 개념으로 덮어써진다.
- 페이지나 layout 에서만 metadata를 내보낼수있다.
- 서버컴포넌트에서만 사용할수있다.

- 최상단 layout.tsx 파일에 metadata 부분에 template 을 넣을수도있다.
- %s 은 string 변수
- metadata를 찾을수없으면, default. 값이 보여진다.
- Not-found.tsx 파일에도 추가해주면 없어진다.
[ Dynamic router ]
경로 : http://localhost:3000/movie/1


[ fetch data ]
- client side 에서 fetch data 할때는, API 를 반드시 사용하여 로딩을 구현하고, metadata를 쓸수없고, useState, useEffect를 써야만했다.
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Movie",
description: "Linker App Movie page",
};
const URL = "https://nomad-movies.nomadcoders.workers.dev/movies";
async function getMovies(){
const response = await fetch(URL)
const json = await response.json();
return json;
}
export default async function MovieDetail({
params:{id},
}:{
params:{id:string};
}){
const movies = await getMovies();
return(
<div>
<h1>movie detail {id}</h1>
{JSON.stringify(movies)}
</div>)
}
- 추가로, nextjs framework 가 fetch 된것을 cash 해두어 여러번 페이지가 변경되도, 어떤데이터가 불러왔는지 기억해서 가져오는데 속도를 향상시킨다.
- server component 이기때문에, client side에서의 요청이없다. 민감한데이터가 감쳐진다.
[ Loading Component ]

- 그냥 loading.tsx 만만들면, server component 에서 불러오는 시간이 길면 로딩컴포넌트를 보여준다.
- Streaming 서비스와 똑같다. html을 chunk 로 나눠서 준비된것들을 먼저 클라이언트에 전달한다.
- 반드시 page.tsx 파일을 포함하는 디렉토리에 loading.tsx 를 만들어줘야한다.
[ Parallel Requests ]
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Movie",
description: "Linker App Movie page",
};
const URL = "https://nomad-movies.nomadcoders.workers.dev/movies";
async function getMovie(id:string){
// await new Promise((resolve)=> setTimeout(resolve, 5000));
const response = await fetch(`${URL}/${id}`)
const json = await response.json();
return json;
}
async function getVideos(id:string){
const response = await fetch(`${URL}/${id}/videos`)
const json = await response.json();
return json;
}
export default async function MovieDetail({
params:{id},
}:{
params:{id:string};
}){
const movie = await getMovie(id);
const video = await getVideos(id);
return(
<div>
<h1>movie detail {id}</h1>
{movie.title}
</div>)
}
- 위 코드는 getMovie(), getVideos() 비동기함수가 순차적으로 이루어진다
- 병렬로 코드를 실행하는방법
const [movie, viedos] = await Promise.all([getMovie(id), getVideos(id)])
[ Error Handling ]
- app/error.tsx 파일을 생성한다.
"use client"
export default function ErrorPage(){
return <h1>L0L something broke....</h1>
}
- 만약 비동기처리시 에러가 난다면, 해당 부분에 표기된다.
- 주의점, 반드시 “use client” 여야한다. 이유는 클라이언트페이지에 랜더링 되기때문
[ CSS modules ]

- navigation.module.css 파일을 만든다.
- 중요한점은 module.css 로 무조건 끝나야한다.
- 파일의 위치는 상관없다. 이름도 상관없다.
- 단반드시 모두 className 으로 시작해야한다.

- styles 오브젝트안에 css 객체가 포함되어있다.
- className 자체에 직접 접근하는것처럼 사용할수 있다.
- 이렇게 사용하면, 공통된 클래스를 가지더라도 전체 스타일 중복을 방지할 수 있다.
[ Dynamic metadata ]
import MovieInfo, { getMovie } from "@/components/movie-info";
import MovieVideos from "@/components/movie-videos";
import type { Metadata } from "next";
import { Suspense } from "react";
// export const metadata: Metadata = {
// title: "Movie",
// description: "Linker App Movie page",
// };
interface IParams{
params:{id:string}
}
export async function generateMetadata({params:{id}}:IParams){
const movie = await getMovie(id)
return{
title:movie.title
}
}
export default async function MovieDetail({
params:{id},
}:IParams){
return(
<div>
<h1>movie detail {id}</h1>
<Suspense fallback={<h1>Loading movie info</h1>}>
<MovieInfo id={id}/>
</Suspense>
<Suspense fallback={<h1>Loading video info</h1>}>
<MovieVideos id={id}/>
</Suspense>
</div>)
}
- 파라미터는 generateMetadata 함수에도 전달된다.
- export 하는것을 잃어버리면안된다. metadata생성시에 참조하게된다.
[ Prefetch ]

Link에 들어가기전에 미리 로드시킨다.


