NextJS 이해 해보기_3 - Client Component

박재현·2024년 6월 9일
1

NEXT.JS

목록 보기
11/17
post-thumbnail

이전 포스팅에서는 NextJS App Route 에서의 Server Component에 대해서 공식문서를 기반으로 정리를 해봤다.

이번에는 Server Component를 했으니 Client Component 차례다!

Server Component대비 Client Component는 비교적 간단한 편인데, Client Component만 잘 이해해도 서로다른 두개의 컴포넌트를 잘 구분할 수 있을것 같다.


Client Component

클라이언트 컴포넌트를 사용하면 서버에서 인터랙티브한 UI를 미리 렌더링할 수 있고(이를 pre-rendered라고 함) 클라이언트의 브라우저에서 자바스크립트를 사용해서 실행할 수 있다.

사실 개인적으로 Client Component와 CSR이 많이 헷갈렸는데 뭔가 둘다 Clinent의 브라우저에서 렌더링이 될거같다는 생각을 했다.

그도 그럴것이 클라이언트 컴포넌트 또한 브라우저에서 자바스크립트를 다운로드 받아야 하니까 그렇게 생각했다.

하지만 Client Component도 기본적으로는 서버에서 렌더링이되는데 Hydration 과정이 Client's Browser에서 이루어 진다.

(반대로 Server Component는 렌더링이 서버에서 이뤄지고, Hydraion 과정이 필요가 없다.)


Client Component의 이점

클리이언트 컴포넌트 또한 아래와 같이 몇가지 이점을 가지고 있다.

상호작용(Interactivity)

클라이언트 컴포넌트는 useState, useEffect 같은 React Hook 그리고 Event Listener 들을 사용할 수 있다.

즉 사용자에게 즉각적인 피드백과 UI 업데이드가 가능하다는 장점이 있다.

Browser APIs

클라이언트 컴포넌트는 Browser에서만 사용가능한 API들을 사용할 수 있도록 도와준다.

예를 들어서, 날씨나 위치 정보를 제공하고 싶을대 필요한 Geolocation이나, 어떤 정보를 브라우저에게 기록해두고 싶을때 사용하는 Local Storage 같은 기능들을 사용할 수 있다.


NextJS에서 Client Component 사용하기

클라이언트 컴포넌트를 사용하기 위해서는 "use client" 라는 지시어를 paget.tsx 파일의 가장 상단에 적어주면 된다. (가장 상단이다, 모듈을 import 하는 부분보다 더 위에 적어줘야 하는데 그냥 첫번째 line에 적어주자.)

"use server"
그렇다면 서버 컴포넌트는 위와같은 지시어를 적어주면 되겠네?
Nope!
NextJS App Route는 기본적으로 모는 컴포넌트가 Server Component로 렌더링한다.
"use server" 라고 적어야 하는 부분은 Server Action에 해당된다.
Server Action이 궁금하면 공식문서 참고!

"use client" 지시어는 서버 컴포넌트와 클라이언트 컴포넌트의 경계를 나눌때 사용한다.

무슨 말이냐 하면 "use client" 라는 지시어를 사용하면, 모든 하위 컴포넌트를 포함해서 해당 파일로 import한 다른 모듈 또한 클라이언트 번들의 일부로 간주하게 된다.

'use client'
 
import { useState } from 'react'
 
export default function Counter() {
  const [count, setCount] = useState(0)
 
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}

만약 아래의 사진과 같이 toggle.js 파일에서 onClick 그리고 useState 를 중첩해서 사용하고 있는데 "use client" 를 파일의 상단에 선언해주지 않으면 에러가 발생한다.

왜냐하면 NextJS App Route에서는 기본적으로 모든 컴포넌트를 Server Componet로 간주한다. 따라서 Server Component에서는 Interactive + Browers API's를 사용할 수 없기에 에러가 발생되게 된다.

이럴때는 toggle.js 파일의 상단에 "use clinent" 지시어를 상단에 추가해주면 해결된다.

"use client" 지시어 여러개 남발하기!
"use client" 지시어를 여기저기 남발해서 사용할 수 있다.
하지만! "use client" 지시어를 굳이 굳이 여기저기 다 사용할 필요는 없다.
바운더리가 되는 가장 상단의 파일에서 한번만 해당 지시어를 사용해주면 된다.
왜냐하면 import 하는 모든 모듈과 자식 컴포넌트들은 알아서 클라이언트 컴포넌트의 일부가 되기 때문이다.

자, 자세히 한번 살펴보자!

위 사진을 잘 보면 실제로 useState를 사용ㅇ하는 부분은 use-toggle.js 파일이다.

하지만 "use client" 지시문을 추가한건 toggle.js 파일이다.

따라서 toggle.js 파일에서 imported 된 모든 모듈과 자식 컴포넌트들은 알아서 클라이언트 컴포넌트의 일부로 인식되게 된다.

쉽죠잉?


클라이언트 컴포넌트는 어떻게 렌더링 될까?

NextJS에서 클라이언트 컴포넌트는 "전체 페이지를 로드 해야할 경우" 또는 "Subsequent Navigations"에 따라 렌더링이 다르게 이뤄진다.

먼저 전체 페이지(Full Page)는 Application에 최초로 처음 방문했을때 혹은 브라우저를 새로고침을 해서 페이지가 다시 로드될때를 의미한다.

그리고 Subsequent Navigations는 아마 Navigation 다음에 진행된다는 의미로보인다.

그래서 Link 컴포넌트나, useNavigation훅을 이용해서 push 등등을 사용한 다음을 의미하는것으로 보인다.

여튼 두가지 다른 방식의 렌더링에 대해서 알아보자.

Full Page Load

초기 페이지 로드를 최적화 하기 위해서 NextJS는 React의 API를 사용해서 서버 컴포넌트 및 클라이언트 컴포넌트 모두 정적인 HTML 페이지를 서버에서 미리 만들어 둔다. (Pre-Rendered!!!)

이 말이 무슨말이냐?

바로 사용자가 처음에 Application(그냥 내가 만든 웹사이트의 어떤 페이지 라고 하자)을 방문하자마자 바로 즉각적으로 컨텐츠가 들어있는 페이지를 볼 수 있다!

이때 중요한건 바로, 사용자가 HTML을 보기 위해서 서버로부터 JavaScript를 다운로드해서 파싱하고 실행할 필요가 없다는것!

왜??
서버에서 HTML을 미리 다 만들어 뒀고, 사용자가 오면 바로 미리 만들어둔 HTML을 보여주기 때문에.
npm run build 후 산출물을 찾아보면 html들을 볼 수 있다.
또 생각보다 많은 페이지들이 staic page인걸 볼 수 있다.

그러면 서버에서는

  1. 리액트는 클라이언트 컴포넌트에 대한 참조를 포함하는 RSC Payload(React Server Component Payload)라는 특수한 데이터 형식으로 서버 컴포터는르를 렌더링 한다.

  2. NextJS는 RSC Payload 및 클라이언트 컴포넌트 자바스크립트 설명서(지침서?)를 기반으로 서버의 경로에 대한 HTML을 렌더링 한다. (경로,Route가 아무래도 유저의 브라우저로 부터 요청이 들어온 URL을 의미하는게 아닐까 싶다.)

그러면 클라이언트에서는

  1. 렌더링된 HTML은 Route에게 초기에 즉각적으로 빠른 프리뷰를 보여주는데, 이때는 단순히 서버에서 렌더링된 HTML이기에 Non-Interactive한 HTML이다.

  2. React Server Component Payload는 클라이언트 및 서버 컴포넌트 트리를 조정하고 DOM을 업데이트 하는데 사용된다.

  3. 자바스크립트 Instructions는 클라이언트 컴포넌트를 Hydration하고 해당 UI를 인터렉티브하게 만든다.

Subsequent Navigations

이 경우에 클라이언트 컴포넌트는 서버에서 렌더링된 HTML 없이 완전히 클라이언트에서 렌더링 된다. (rendered entirely on the client!)

이는 클라이언트 컴포넌트 자바스크립트 번들이 다운로드되고 분석(parse) 된다는 의미로, 번들이 준비되면 리액트는 RSC Payload를 사용해서 클라이언트 및 서버 컴포넌트 트리를 조정하고 DOM을 업데이트 한다.

사실 생각해보면 Link나 useNavigation 같은 훅을 사용한다면 href로 외부 URL을 넣어줄수도 있을거고, 그렇다면 프레임워크 입장에서 빌드할때는 어떻게 동작될지 예상이 불가능할거같기는 하다.


서버 환경으로 낼럼 돌아가기

때때로 "use client" 라는 지시어를 사용한 다음에도 서버환경으로 돌아가고 싶을때가 있다.

무슨 말이냐면

  • 클라이언트가 다운로드 해야할 번들의 크기를 줄이고 싶다거나
  • 서버에서 외부 데이터를 갖고오고 싶다거나 (data fetch or DB 조회)

이럴때는 코드가 이론적으로는 클라이언트 컴포넌트 내부에 위치해 있더라도 "Server Action"을 사용하면 코드를 계속 서버에 유지시킬 수 있다!


다시한번 느끼지만 영어공부가 더 급하다...

참고

profile
기술만 좋은 S급이 아니라, 태도가 좋은 A급이 되자

0개의 댓글

관련 채용 정보