s e o p p o r t . l o g

Today I Learned

서버컴포넌트에서 zustand 사용하기?

Seo Ji Won 2024. 4. 16. 17:24

 

페이지 컴포넌트에서 HTML태그와 컴포넌트를 분리해서 깔끔하게 만들고 싶었다.

export default async function ReservePage({ searchParams }: { searchParams: { classId: string } }) {
  const classId = searchParams.classId;
  const classInfo = await fetchReserveClassInfo(classId);

  return (
    <div className="min-h-100vh-header bg-light-purple flex py-6">
      {classInfo ? (
        <div className="w-full  box-border  bg-light-purple flex justify-center items-center flex-col text-gray-600 lg:flex-row ">
          <div className="flex box-border flex-col w-[400px]">
            <ClassInfo classInfo={classInfo} />
            <ReserveUserInfo />
          </div>
          <div className="lg:divider-horizontal"></div>
          <div className=" py-6  px-12 w-[400px] h-[804px] bg-white rounded-md  justify-between flex flex-col shadow">
            <p className="font-bold text-lg text-left w-full mb-1">수강일 선택하기</p>
            <DateTimePicker classDates={classInfo.dates} />
            <CurrentReserveQuantity classId={classInfo.classId} maxPeople={classInfo?.maxPeople} />
            <PriceCalculator price={classInfo.price} classId={classInfo.classId} maxPeople={classInfo.maxPeople} />
            <ReserveButton classId={classInfo.classId} maxPeople={classInfo.maxPeople} title={classInfo.title} />
          </div>
        </div>
      ) : (
        <p>클래스 정보를 불러오지 못했어요. 🥲</p>
      )}
    </div>
  );
}

그래서 일단 컴포넌트들을 분리하고, 프롭 드릴링으로 내려주는데 드릴링이 최대 2번이긴 하지만 프롭스를 사용하지 않고 자식에게 전달만 하는 컴포넌트 생겨 비효율적이라고 판단했고 zustand를 사용해 서버에서 불러와서 state에 저장하고 전역상태로 관리하려고 하였다.

그런데 생각해보니 서버컴포넌트(페이지)에서는 zustand를 못쓰는것이 아닌가?(페이지 컴포넌트를 client 컴포넌트로 사용하고 싶지 않았다) 해서 그냥 프롭 드릴링으로 하려다가

서버컴포넌트에서도 zustand를 사용할 수 있다는 글을 보았다 recoil, jotai같은 리액트 훅을 사용하여 만들어진 전역상태관리 라이브러리는 쓸 수 없지만 서버컴포넌트에서 바로 store를 만들어서 쓸 수 있다는 것이다

그런데 글을 좀 더 찾아보니 SSR에서 zustand를 사용하면 작동하는 것처럼 보이지만 실제로는 예상치못한 버그가 발생할 수 있다고 하여 사용을 권장하지 않는다고 한다. (대충 서버측에서 캐시된 데이터가 다른 사용자가 페이지에 접근했을 때 새로운 데이터를 불러오지않고 캐시된 데이터로 남아있는 버그.. 등등) 

해결책으로는 SSR에서 데이터를 불러오고, 클라이언트 컴포넌트로 넘겨준 다음 클라이언트 컴포넌트에서 zustand에 값을 업데이트하는 방식을 쓸 수 있다는데 useEffect를 사용하면 값이 들어왔을 때 리렌더링이 일어날거고 프롭드릴링 한번 줄이자고 이렇게까지 해야하나.. 싶은 생각이 들었다.

그래서 생각했던 방법은 사용하지 않고

프롭 드릴링 vs 약간 지저분한 코드 의 문제인데 뭐가됐는 성능이 더 중요하지 않을까 싶어 그냥 놔두기로 결정했다

 

참고한글

Add a warning to readme about React Server Components by ADTC · Pull Request #2202 · pmndrs/zustand · GitHub

Using Zustand in React Server Components - misguided misinformation and misuse? · pmndrs/zustand · Discussion #2200 · GitHub