키모스토리

#31. 서드파티 UI 패키지, Context Providers 본문

Web Devlopment/NextJs

#31. 서드파티 UI 패키지, Context Providers

키모형 2025. 12. 30. 20:08
반응형

아래 내용은 Next.js App Router(v15~v16) 기준으로, react-slick 같은 서드파티 UI 패키지를 “클라이언트 라우트(=Client Component 영역)”와 “서버 라우트(=Server Component/Route Handler 영역)”에서 안전하게 쓰는 패턴 + Context Providers까지 한 번에 정리한 글입니다.

1) “서드파티 UI 패키지”는 어디에서 써야 하나?

App Router에서 page.tsx / layout.tsx는 기본이 Server Component입니다. 서버 컴포넌트는 DB 접근/시크릿 사용/JS 번들 감소/스트리밍에 유리하고, 브라우저 API나 상호작용이 필요하면 Client Component를 섞어서 씁니다. Next.js

따라서 서드파티 패키지는 보통 아래처럼 분류하면 편합니다.

A. “클라이언트 전용 UI 패키지” (react-slick 같은 케이스)

  • 내부에서 useState, useEffect, createContext 또는 window/document 등을 사용
  • Client Component에서만 사용 (파일 상단에 'use client')
  • 그리고 SSR에서 깨지면 ✅ dynamic(..., { ssr:false })로 클라이언트 전용 로딩 Next.js

Next 문서도 “서드파티 컴포넌트가 아직 "use client"를 붙이지 않은 경우가 많다 → 내 프로젝트에서 Client wrapper로 감싸라” 패턴을 안내합니다. Next.js

B. “서버 전용/노드 전용 패키지” (암호화, 파일, DB 드라이버 등)

  • ✅ Server Component / Route Handler(route.ts)에서 사용 가능
  • Next는 서버 컴포넌트/Route Handler에서 쓰는 의존성을 번들링하고, 필요 시 serverExternalPackages로 번들링을 제외할 수 있습니다. Next.js

2) react-slick을 App Router에서 쓰는 “정석” 패턴

(1) CSS(외부 스타일) 처리

react-slick는 보통 slick-carousel CSS를 같이 씁니다.

App Router에서는 외부 패키지 CSS를 app 디렉토리 어디서든 import 가능하지만, 전역 스타일 충돌을 피하려면 보통 root layout 또는 전역 CSS에서 한 번만 넣는 걸 권장합니다. Next.js

예) app/layout.tsx 또는 app/globals.css에서 한 번만:

// app/layout.tsx
import "./globals.css";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";

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

 

(2) Client Component로 “슬라이더 위젯” 만들기

react-slick는 SSR에서 window 이슈가 나는 경우가 많아서, 안전하게 dynamic + ssr:false를 자주 씁니다. (ssr:false는 브라우저 API 의존 컴포넌트에 유용하다고 문서에서 안내합니다.) Next.js

// components/Carousel.client.tsx
"use client";

import dynamic from "next/dynamic";

// Slider를 클라이언트에서만 로드
const Slider = dynamic(() => import("react-slick"), { ssr: false });

export function CarouselClient({ images }: { images: string[] }) {
  const settings = { dots: true, infinite: true, slidesToShow: 1, slidesToScroll: 1 };

  return (
    <Slider {...settings}>
      {images.map((src) => (
        <div key={src}>
          <img src={src} alt="" />
        </div>
      ))}
    </Slider>
  );
}

참고: Client Component는 async function이면 에러가 납니다. (클라이언트 컴포넌트는 async를 지원하지 않음) Next.js

(3) Server Route(=page.tsx)에서는 “데이터만 준비하고 Client 위젯을 끼워 넣기”

서버 컴포넌트에서 react-slick를 직접 import하면 문제가 나기 쉽습니다. 문서에서 안내하는 것처럼 서드파티 UI는 Client wrapper로 감싸서 서버에서 렌더 트리에 포함시키는 방식이 안전합니다. Next.js+1

// app/product-reviews/page.tsx (Server Component)
import { CarouselClient } from "@/components/Carousel.client";

export default async function Page() {
  // 서버에서 데이터 준비(DB/API 가능)
  const images = ["/a.jpg", "/b.jpg", "/c.jpg"];

  return (
    <div>
      <h1>Product Reviews</h1>
      <CarouselClient images={images} />
    </div>
  );
}
 
 

3) Context Providers(전역 상태/테마/인증) 패턴

(1) Provider는 무조건 Client Component로 분리

createContext는 Server Component에서 사용할 수 없고, “Provider 파일에 'use client'를 붙이라”고 안내합니다. Next.js

// app/providers.tsx
"use client";

import { ReactNode } from "react";

export default function Providers({ children }: { children: ReactNode }) {
  return (
    <>
      {children}
    </>
  );
}

 

그리고 root layout(Server Component)에서 감싸기:

// app/layout.tsx (Server Component)
import Providers from "./providers";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ko">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
 
(2) “서버에서 가져온 초기 데이터”를 Provider에 주입하는 방법

Next 문서에는 Promise를 await 하지 말고 Provider로 내려보낸 뒤, 클라이언트에서 use()로 풀어 쓰는 패턴도 소개되어 있습니다. (이 방식은 일찍 fetch를 시작하고, 소비 컴포넌트가 suspend 되며 부분 스트리밍/하이드레이션에 도움이 됩니다.) Next.js+1

요지는:

  • 서버: const userPromise = getUser() (await 금지)
  • 클라 Provider/Hook: 컨텍스트로 promise 전달
  • 클라 소비 컴포넌트: use(userPromise)로 언랩

(문서 예시는 그대로 참고하셔도 좋습니다.) Next.js


4) “서버 라우트(route.ts)”에서는 어떻게 쓰나?

app/api/.../route.ts 같은 Route Handler는 서버에서만 실행됩니다.
따라서 react-slick 같은 UI 라이브러리를 여기서 쓰는 건 의미가 없고, 대신 Node 전용 패키지(암호화/SDK/DB 유틸 등) 는 사용 가능합니다.

또한 Next는 서버 컴포넌트/Route Handler에서 쓰는 의존성을 자동 번들링하며, Node 특화 패키지라 번들링이 문제가 되면 serverExternalPackages로 제외할 수 있습니다. Next.js


실무 요약 체크리스트

  • react-slick 같은 UI 패키지 → components/*.client.tsx로 분리 + 필요 시 dynamic(..., { ssr:false }) Next.js+1
  • Server page.tsx → 데이터 준비만 하고 Client 위젯을 렌더 트리에 끼우기 Next.js+1
  • Provider(createContext) → 반드시 'use client'로 분리 후 root layout에서 감싸기 Next.js
  • Client Component는 async 금지 (데이터는 서버에서 준비하거나 Provider+Promise 패턴 활용) Next.js+1
반응형