보일러 플레이트
프로그래밍이나 법률 문서에서 반복적으로 사용되는 표준화된 코드나 텍스트를 의미한다. 즉 기본적으로 사용할 수 있는 템플릿이나 초기 설정을 말하고 이로 인해 반복적인 설정 작업을 줄여 빠르게 초기 설정을 할 수 있다.
// npx create-next-app@latest
✔ Would you like to use TypeScript? … No / Yes --> yes
✔ Would you like to use ESLint? … No / Yes --> yes
✔ Would you like to use Tailwind CSS? … No / Yes --> yes
✔ Would you like to use `src/` directory? … No / Yes --> no
✔ Would you like to use App Router? (recommended) … No / Yes --> yes
? Would you like to customize the default import alias (@/*)? › No / Yes. --> no
App Router
app/
├── blog/
│ └── page.tsx --- /blog // blog 컴포넌트
├── about/
│ └── page.tsx --- /about // about 컴포넌트
// auth 폴더 안에 login폴더, register폴더와 layout 파일이 형성
auth/
├── login/
│ └── page.tsx --- /login // login 컴포넌트
├── register/
│ └── page.tsx --- /register // register 컴포넌트
└── layout.tsx
// layout.tsx
export default function layout({ children }: { children: React.ReactNode }) {
return (
<>
<h3>auth Header</h3>
{children}
<h3>auth Footer</h3>
</>
);
}
=> 라우트 경로에서 가장 가까운 곳에 위치한 layout 파일을 찾고 해당 layout은 login 컴포넌트와 register 컴포넌트를 children으로 props을 받는다.
app/
├── login/
│ └── page.tsx --- /login
├── register/
│ └── page.tsx --- /register
app/
└── auth/
├── page.tsx - /login
└── register/
└── -page.tsx -- /register
app/
└── blog/
├── page.tsx - /blog
└── [id]/
└── page.tsx -- /blog/1 or /blog/2 or /blog/3...
app/
└── blog/
├── page.tsx - /blog
└── [id]/
├── page.tsx -- /blog/1 or /blog/2 or /blog/3...
└── comment/
└── [reviewId]/
└── page.tsx. -- /blog/2/comment/1
app/
└── docs/
└── [...slug]/
└── page.tsx - /docs/1 or /docs/1/api or /docs/1/api/1 등등 모든 경로 커버 가능
const Docs = ({
params,
}: {
params: {
slug: string[];
};
}) => {
console.log(params); // /docs 이후의 경로가 배열로 들어감 ex_/docs/1/user/1 -> [1, user, 1]
return (
<>
<h1>Docs Component</h1>
</>
);
};
export default Docs;
app
(home)
page.tsx --- /
(auth)
login
page.tsx --- /login
register
page.tsx --- /register
app
_utils
page.tsx - 접근 불가
form-date.ts
// not-found.tsx
const NotFound = () => {
return (
<>
<h1>요청하신 페이지를 찾을 수 없습니다.</h1>
</>
);
};
export default NotFound;
라우팅
import Link from "next/link";
<Link href={"/products"}>Products</Link>
'use client';
import { useRouter } from 'next/navigation';
export default function Blog(params: any) {
const router = useRouter();
return (
<>
<h1>Blog Component</h1>
<button onClick={() => router.back()}>Go Back</button> // 현재 페이지 기준으로 이전으로 이동 (뒤로 가기)
<button onClick={() => router.forward()}>Go Forward</button> // 현재 페이지 기준으로 다음으로 이동 (앞으로 가기)
<button onClick={() => router.push('/about')}>Go to About</button> // url로 이동 후 브라우저 기록에 항목 추가
<button onClick={() => router.replace('/about')}>Replace to About</button> // url로 이동 후 브라우저 기록 덮음
<button onClick={() => router.refresh()}>Refresh Page</button> // 현재 페이지 다시 로드
</>
);
}
Hydration
❓ 2번 렌더링 ❓
서버에서 렌더링된 HTML 페이지가 클라이언트에게 전송되고 클라이언트는 서버에서 전송된 HTML 페이지를 받아 브라우저에 렌더링을 하면서 2번의 렌더링이 발생한다. 이 과정에서 비효율적으로 생각할 수 있다.
하지만
서버에서 렌더링 된 HTML은 가벼운 파일로써 사용자에게 빠르게 로드되는 웹 페이지를 제공할 수 있다.
클라이언트에서 js 파일이 로드되고 하이드레이션 과정이 시작될때 react는 이미 서버에서 렌더링된 HTML을 사용하여 DOM 요소와 매칭하므로 다시 웹페이지를 그리지 않는다.
폰트 최적화
// global.css
@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');
.roboto {
font-family: 'Roboto', sans-serif;
}
// page.tsx
import { Roboto } from 'next/font/google';
const roboto = Roboto({ weight: ['400', '700'], subsets: ['latin'] });
export default function Main() {
return (
<>
<h1 className="roboto">Main page Component</h1> // 폰트 최적화 적용x
<h1 className={roboto.className}>Main page Component</h1> // 폰트 최적화 적용o
</>
);
}
위 코드 처럼 비교를 위해 각각 h1태그를 띄어줘고 개발자도구 네트워크 탭에서 캐시 사용 중지로 설정을 하고 새로고침을 했을경우 아래와 같이 폰트 최적화 한 태그와 반대로 폰트 최적화 안 한 첫 번째 h1태그는 아래와 같이 깜박임을 보면서 차이를 확인할 수 있다.
Lighthouse로 폰트 최적화 한 태그와 안 한 태그의 차이를 h1 태그로 각각 비교해본 결과로
LCP(가장 큰 콘텐츠가 포함된 페인트. 즉 가장 큰 콘텐츠를 렌더링 하는데 걸리는 시간)을 보면 폰트 최적화를 안 한 결과는 1.76초, 폰트 최적화를 한 결과는 0.49초로 콘텐츠 요소가 렌더링 되는 시간의 차이를 볼 수 있고 성능 점수 또한 91점 과 99점의 차이를 비교해 볼 수 있었다.
그래서 정리 하자면
폰트 최적화를 안 한 경우
서버에서 HTML을 생성할 때 기본 폰트로 적용되며 클라이언트는 받은 HTML 페이지를 렌더링하는 동안 해당 폰트 파일을 다운로드해 적용한다.
클라이언트가 페이지를 받아온 후에 해당 폰트 파일을 다운로드해 적용하기 때문에 위에서 비교한 내용 처럼 초기 콘텐츠 렌더링하는 시간이 더 걸리면서 새로고침 시 깜박임이 발생한다.
폰트 최적화를 한 경우
서버에서 HTML을 생성할 때 이미 폰트가 적용된 HTML 페이지를 클라이언트가 받아 렌더링 한다.
이미 폰트가 적용되어 있기 때문에 별도의 폰트 파일을 다운로드 할 필요가 없어 초기 렌더링 시간이 폰트 최적화 안 한 경우보다 빠르며 깜박임이 없다.
전에 기초부분만 맛만 본 Next.js로써 자세히 학습하지 않았지만 이번 강의를 통해서 기초를 다지면서 실습을 통해 많이 얻어갔다. Hydration에 대해 이해하려고 하면서 렌더링 과정 부분에도 다시 한번 학습이 필요한걸 깨달았고 자료와 강의를 통해 부족한 부분을 알아가고 채워가면서 익숙해져본다