Next.js 시작하기( ROUTING 2 )

짜스의 하루 ·2024년 7월 21일

'use client'

자, 저번 시간에
next.js에서는 서버 사이드에서 페이지를 렌더링하여 정적인 HTML 파일을 생성한다.
클라이언트가 이 HTML 파일을 처음 로드할 때, 페이지는 아직 동적 기능이 적용되지 않은 상태

이후 클라이언트는 자바스크립트 파일과 Next.js 프레임워크를 다운로드하고 실행한다.
이 단계에서 자바스크립트는 페이지의 HTML 요소에 이벤트 리스너를 추가하고 동적 기능을 활성화한다.

이러한 과정을 하이드레이션이라고 한다.

하이드레이션은 클라이언트에서 자바스크립트가 HTML에 액티브한 기능을 추가하여 동적 기능을 활성화하는 과정이다.
이로 인해 페이지의 인터랙션(버튼 클릭, 네비게이션 등)이 가능해진다.

그럼, 모든 파일에, 모든 컴포넌트에 하이드레이션 과정을 거쳐야 할까?
--> 아니다!

만약 이 페이지를 예를 들자면, 단순히 <h1/> 태그만을 가지고 있는 정적인 콘텐츠만 포함하고 있는 페이지를 하이드레이션 과정을 거칠 필요가 있을 까? --> 없다.

이는 그냥 지루한 HTML파일로만 납둬도 상관이 없다

그럼 어떤건 하이드레이션 과정이 필요하고, 어떤건 하이드레이션 과정이 필요가 없는데, 어떻게 판단하지?
--> "use client"를 추가해주면 된다.

"use client"와 하이드레이션

"use client" 지시어는 Next.js의 앱 라우터에서 사용되는 것으로, 클라이언트 측에서만 실행되는 컴포넌트를 정의한다.
--> 즉, 해당 컴포넌트는 클라이언트에서 렌더링되어야 하며, 자바스크립트가 필요한 기능이 포함되어 있을 때 사용된다.

"use client" 선언: 이 선언이 포함된 파일이나 컴포넌트는 클라이언트에서 실행되며, 하이드레이션 과정이 적용된다.
클라이언트 측의 상태 관리, 이벤트 핸들링, 상호작용 등이 필요할 때 사용된다.

미포함 : "use client" 선언이 없는 컴포넌트는 서버 사이드 렌더링에 의해 렌더링되며, 클라이언트에서 하이드레이션이 필요하지 않은 경우가 많다.

간단하게 요약하자면
1 . 서버 사이드 렌더링: 서버는 모든 컴포넌트를 정적인 HTML로 렌더링하여 클라이언트에 전달한다. 이 단계에서 클라이언트는 서버에서 생성된 정적 HTML을 먼저 로드하게 된다.

2 . "use client"가 포함된 파일: "use client"가 포함된 컴포넌트는 클라이언트 측에서 렌더링되고, 자바스크립트가 실행되며, 동적 기능이 활성화된다.
--> 이 컴포넌트는 클라이언트에서 하이드레이션 과정을 거쳐서 동적 상호작용이 가능하게 된다.

이로써 , 자바스크립트 최적화: "use client"를 사용하여 동적 기능이 필요한 부분만 자바스크립트로 처리하게 하여 다운로드해야 할 자바스크립트 파일의 양을 줄일 수 있게 된다!


Recap

지금까지 배운걸 정리해보는 시간을 가져보자

먼저, Next.js는 우리가 언제 어느 페이지로 이동을 하던, (사용자에게 응답이 주어지기 전에) 백엔드에서 우리 application을 pre render을 하게 된다

모든 component를 가져아서 지루한 HTML로 바꾸게 된다.

이후 사용자가 우리 웹사이트에 도착하자마자, 우리는 이 지루한 HTML을 전달하고, 그리고 나서 프레임워크나 Reat.js를 initialize를 하게 된다.

그리고 나면 , "use client" 명령어를 가진 component가 hydrate되게 된다.
--> hydrate는 interactive 되어진다는 뜻을 의미한다.


Layout

기본적으로 하나의 블로그가 있다고 가정해보자.
블로그에는 Header, nav, Footer들이 어떤 링크를 타고 들어가도 똑같이 화면에 나타나는 것을 확인할 수 있다.
--> 이러한 공유되는 것들을 Layout에 공유하면 된다.

next.js는 파일이 처음 로딩될 때, Layout.tsx 에서 파일을 쫙 로딩한 뒤, 링크를 확인한다. 만약 /about-us라면,

<Layout>
  <AboutUs/>
</Layout>

이런식으로 로딩이 되는 것이다.

즉 , 사용자가 /about-us 경로를 방문하면, Next.js는 Layout 컴포넌트와 AboutUs 페이지 컴포넌트를 조합하여 최종 페이지를 생성하게 된다.

Layout.tsx

export const metadata = {
  title: 'Next.js',
  description: 'Generated by Next.js',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

가장 기본적은 Layout.tsx 파일을 살펴보면, {children}에 <AboutUs/> 가 위치한다고 생각하면 된다.

정리하자면, next.js는 Layout 컴포넌트를 렌더링하고, 이동하려는 페이지의 url를 통해 인식해서 Layout 컴포넌트안에 해당 페이지를 렌더링하게 되는 것이다.

어떤 페이지로 이동하게 될때마다, 이 레이아웃 컴포넌트가 렌더링되고, 내가 가려는 페이지게 {children}이 되는 것을 나타낸다.

그럼 이전에 모든 페이지마다, <Navigation/> 컴포넌트를 추가했던 것을, Layout 컴포넌트에 추가하면 딱 좋겠다!

그럼, about-us만의 Layout을 만들어보자!


어? 그럼 http://localhost:3000/about-us에 들어가면 about-us에 생성한 layout만 적용되는거 아니야?

아니다! --> layout은 중첩된다!
http://localhost:3000/about-us로 링크를 들어간다고 가정한다면,

app 폴더에 있는 layout이 먼저 실행된다.

이 RootLayout이 먼저 실행된 후, url를 보고 about-us 로 이동하는 것을 판단 한 후, about-us 폴더에서 layout을 찾는다.

그럼

<RootLayout>
  <AboutUsLayout>
    { chileren } ==> about-us의 page.tsx
  </AboutUsLayout>
</RootLayout>

이렇게 실행되는 것을 확인할 수 있다.


짠 ! 페이지에서도 이렇게 나타나는 것을 확인할 수 있다!

about-us/company/jobs/sales/page.tsx 파일을 생성했다고 가정해보자

그럼,

<RootLayout>
  <AboutUsLayout>
    { chileren } ==> sales의 page.tsx
  </AboutUsLayout>
</RootLayout>

가 실행된다.

간단하게 정의하자면,

RootLayout: 애플리케이션의 최상위 레이아웃으로, 전체 페이지의 공통 요소(예: 전체 레이아웃, 전역 스타일 등)를 정의한다.
AboutUsLayout: : about-us 경로 아래에 있는 페이지들(company, jobs, sales)에 공통적으로 적용되는 레이아웃이다. 이 레이아웃은 about-us 하위 페이지에 대해 적용된다.
페이지 컴포넌트: 각 페이지 컴포넌트(sales/page.tsx)는 자신의 콘텐츠를 정의한다.

<RootLayout> 레이아웃과, <AboutUsLayout> 레이아웃이 적용된 모습을 볼 수 있다.


Metadata

Next.js에서 metadata는 <head> 태그에 넣을 수 있는 요소들이다.
Next.js는 React의 기본 <head> 요소를 확장하여 다양한 메타데이터를 쉽게 설정할 수 있도록 도와준다.
--> 이는 SEO(검색 엔진 최적화) 및 웹 애플리케이션의 성능 향상에 매우 중요하다.

RootLayout에 metadata 정의하기


이렇게 지정할 수 있는데,
(default 값은 : 이상한 링크로 이동 -> 메타데이터를 찾을 수 없기 때문에 default값으로 보여주게 된다)
여기서 title

description은

title은 '%s | Next Movies' 지정해 주었는데, RootLayout에 두었기 때문에 metadata는 모든 페이지에 공유되게 된다.

%s 부분만 각각 페이지로 변경되면 되기 때문에, 공통된 부분(title의 template)은 RootLayout에 지정해두고,

여기서 확인할 수 있는 부분은 메타데이터는 병합된다는 점이다.

그리고 , 중요하게 알고 있어야 하는 점은,
1 . 페이지나 레이아웃에만 메타데이터를 내보낼 수 있다
2 . 컴포넌트는 metadata를 내보낼 수 없고, 또 matadata는 서버 컴포넌트에서만 있을 수 있다. (client 컴포넌트에는 있을 수 없다)

괄호 -> Link로 생성 X


여기서 하나는 (home) 괄호가 쳐져있고, 하나는 괄호가 없는 about-us이다.
나는 분명, app 폴더에 폴더를 하나 생성하면 그게 바로 라우터 역할을 한다고 배웠는데, 그럼 about-us는
http://localhost:3000/about-us가 되는데
(home)은 http://localhost:3000/(home)이 되는건가?

놉!!!!! 아니다
Next.js에서는 괄호(())로 감싸진 폴더는 경로로 사용되지 않고, 라우팅에 영향을 미치지 않는다.

이러한 폴더는 보통 논리적인 그룹화레이아웃을 위한 용도로 사용된다.
따라서 app/(home) 폴더는 URL 경로에 영향을 주지 않고, 해당 폴더 내부에 있는 페이지들이 http://localhost:3000/ 경로로 접근되게 된다.

URL 매핑

  • (home)/page.js: 이 파일은 http://localhost:3000/ 경로로 접근된다.
  • about-us/page.js: 이 파일은 http://localhost:3000/about-us 경로로 접근된다.

(home)/page.js


Dynamic Routes

자, 만약 내가 만들었던 S-FLEX에 접속했다고 가정해보자.
home 페이지에서 영화를 하나 클릭했을 때->
/ -> /movies/12345 로 이동하도록 하려면 어떻게 할 까?

여기서 12345 는 영화의 id라고 가정해보자.
그럼, 단순히 /movies 인 정적인 라우트가 아닌, 영화를 클릭했을 때 해당 영화의 id를 가져온 뒤, id를 라우터에 추가해주어야 하기 때문에 동적 라우트가 적용되어야 한다.

그럼 동적 라우트는 어떻게 만들어야 할 까? --> 대괄호 [] 를 사용해야 한다
--> 이는 동적 경로 세그먼트를 정의하여 URL의 일부로 변수를 사용할 수 있게 한다.

폴더 구조가

app/
  (movies)
  	movies/
    	[id]/
    	  page.js
page.js

로 구성되어 있다고 가정해보자.

그럼 movies/[id] 의 동적 라우터가 만들어진다.
app/(movies)/movies/[id]/page.js 파일이 해당 경로를 처리하게 된다.
(위에서 언급했듯이 (movies)는 단순히 그룹화를 위한 폴더이다)

그럼, 저 [id]를 props로 받아올 수 있을 까?

app/(movies)/movies/[id]/page.tsx

export default function MovieDetail(props) {
  console.log(props);
  return <h1>Movie</h1>;
}

콘솔을 찍어보면,

왜? --> 클라이언트 컴포넌트가 아니기 떄문에 프론트에서 실행되지 않기 때문이다

props를 찍었을 때--> params와, searchParams를 얻어올 수 있다.

내가 url를 http://localhost:3000/movies/123566?page=2로 보냈다면,
업로드중.. params에 id = "123566"을, searchParams에 page = "2"를 받아오는 것을 확인할 수 있다.

그럼, 화면에 id를 출력해보자

export default function MovieDetail({
  params: { id },
}: {
  params: { id: string };
}) {
  return <h1>Movie id : {id}</h1>;
}

params 객체로부터 id 값을 받아와서 해당 영화의 ID를 화면에 출력할 수 있다.

  • params: { id } : 구조 분해 할당 -> param에서 id 만 받아온다.
  • }: { params: { id: string } } : TypeScript를 사용하여 params 객체의 구조를 명시한다. --> params 객체는 id라는 문자열 속성을 가진 객체여야 한다.

[id] 폴더는 동적 경로를 처리하는 폴더이다.
--> 동적 경로 파라미터는 컴포넌트의 params 객체로 전달

업로드중..
이렇게 params로 id를 받아서 화면에 출력하는 것까지 확인할 수 있다

아직 익숙하지는 않지만, react보다 훨씬 간편해진 것 같은 느낌이 든다! 😎

profile
2024. 01. 02 ~ 백앤드 공부 시작, 2024. 04.01 ~ 프론트 공부 시작

0개의 댓글