아래와 같이 Header는 로그인 상태에 따라 UI가 다르다.
로그인 전 header
로그인 후 header
그래서 이것을 구분하기 위해 checkUser()라는 API를 호출해 isLogin 이라는 값을 받아와 구분해주어야 한다.
이외에도 Header에 필요한 notifications, profileImageFilePath와 같은 값을 받아오기 위해 API를 호출한다.
스크롤이 내려가면 Header가 사라지고 스크롤이 올라가면 Header가 보여지게 하는 기능을 제공한다.
(파랑 : 서버 컴포넌트, 빨강 : 클라이언트 컴포넌트)
1. Header는 클라이언트 컴포넌트였다.
Header가 클라이언트 컴포넌트였던 이유는 "스크롤이 내려가면 Header가 사라지고 스크롤이 올라가면 Header가 보여지게 하는 기능"을 제공하기 위해 Header의 Root단에서 useState()를 사용해야 했기 때문이다.
2. Data Fetching이 Page에서 이루어졌다.
빠른 렌더링을 위해 서버 컴포넌트에서 Data Fetching을 했다.
위 구조에서 서버 컴포넌트는 Page였기 때문에 isLogin과 같은 Header에 필요한 Data Fetching이 Page에서 이루어졌다.
-> 각 페이지마다 동일한 Data Fetching 코드를 작성해서 Header에 props로 전달해주어야 한다.
-> 중복 코드 발생, props drilling 문제
3. 내부 컴포넌트 없이 구현했다.
당시 header 이외에도 구현사항이 많아서 빠른 개발을 위해 컴포넌트를 분리하지 않고 구현했다.
-> 코드가 매우 길고 이해하기 어려웠다.
Header component 코드 :
(파랑 : 서버 컴포넌트, 빨강 : 클라이언트 컴포넌트)
1. Header를 서버 컴포넌트로 변경했다.
Next12에서는 page단위의 SSR을 제공했지만 Next 13부터는 컴포넌트 단위의 SSR을 제공한다.
그래서 Header
라는 서버컴포넌트를 만들고 "스크롤이 내려가면 Header가 사라지고 스크롤이 올라가면 Header가 보여지게 하는 기능"은 ScrollAnimationCover
라는 클라이언트 컴포넌트로 두어 스크롤 관련 기능도 제공하면서 Data Fetching이 Header
에서 가능하도록 했다.
2. Data Fetching이 Header에서 이루어졌다.
Data Fetching이 Header
컴포넌트 내에서 이루어지기 때문에 페이지마다 동일한 Data Fetching 코드를 작성해서 Header
에 props로 전달해주는 일이 필요 없어졌다.
-> 중복 코드 문제 해결, props drilling 감소
3. 내부 컴포넌트를 생성해 구현했다.
위 그림처럼 LogoButton
, Navigator
, Submenu
로 내부 컴포넌트를 만들어 구현했다.
다음 코드와 같이 가독성이 훨씬 좋아진 것을 확인할 수 있다.
export default async function Header({ currentPage }: Props) {
const accessToken = cookies().get(ACCESS_TOKEN)?.value;
const refreshToken = cookies().get(REFRESH_TOKEN)?.value;
const cookie = `${ACCESS_TOKEN}=${accessToken}; ${REFRESH_TOKEN}=${refreshToken}`;
const { id, isLogin, authority } = await checkUser(cookie);
const { profileImageFilePath } = isLogin
? await getUserInfo(id)
: { profileImageFilePath: undefined };
const notifications = isLogin ? await getNotificationsTop30(cookie) : [];
return (
<ScrollAnimationCover>
<div className="flex justify-center relative items-center py-4 px-1 sm:px-5 max-w-screen-xl m-auto h-[70px]">
<LogoButton />
<Navigater currentPage={currentPage} />
{isLogin ? (
<Submenu1
authority={authority}
profileImageFilePath={profileImageFilePath}
notifications={notifications}
/>
) : (
<Submenu2 />
)}
</div>
<NavigatorInMobile currentPage={currentPage} />
</ScrollAnimationCover>
);
}
나는 Next13에서 주로 Data fetching을 page 컴포넌트에서 해왔다. 이는 Next 12를 사용하는 것과 다름없다.
Next 12는 페이지 단위의 서버사이드 렌더링을 제공하고 Next 13은 컴포넌트 단위의 서버사이드 렌더링을 제공한다.
Next 13을 사용하는 만큼 서버 컴포넌트를 이해하고 필요한 곳에 잘 사용해야 한다.
서버 컴포넌트와 클라이언크 컴포넌트 구조를 잘 구성해서 Data가 필요한 가장 가까운 위치에 Data Fetching을 하면 Props drilling을 줄이고 중복코드를 줄일 수 있다.
+ 내부 컴포넌트를 생성해 가독성 있는 좋은 코드를 만들자!
RSC vs SSR과 관련한 아주 좋은 글이다.
이 글을 통해 RSC에 대해 이해하고 이러한 리팩토링 작업도 시도해볼 수 있었다.