-
Notifications
You must be signed in to change notification settings - Fork 3
Type‐Safety한 Tailwind Props 타입 관리
공용 컴포넌트나 레이아웃 컴포넌트의 스타일을 커스텀하고 싶을 때 cn
함수를 이용했다.
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
clsx
: 조건부 클래스 네임을 쉽게 조합할 수 있게 도와준다.
tailwind-merge
: TailwindCSS 클래스 테임을 병합하고 중복되거나 불필요한 클래스를 제거하여 최적화된 결과를 제공한다.
아래와 같이 cn
함수를 사용할 수 있다.
import { cn } from "@/lib/utils";
interface HorizontalDividerProps {
className?: string;
}
export default function HorizontalDivider({
className,
}: HorizontalDividerProps) {
return <div className={cn("bg-divider h-0.5 rounded-sm", className)}></div>;
}
하지만 cn
함수와 props로 전달받은 className
로 스타일을 사용하면 공용 컴포넌트를 만들 이유가 없다.
어떤 값이 컴포넌트에서 중요한 역할?을 한다면 그 값을 props로 전달하는 것이 의미적으로 좋다.
ex) <ScrollWrapper />
컴포넌트는 너비와 높이를 전달 받은 width
,height
값으로 제한하고, 스크롤을 할 수 있게 해주는 레이아웃 컴포넌트이다.
import { cn } from "@/lib/utils";
type ScrollWrapperProps = {
width?: string;
height?: string;
children: React.ReactNode;
};
export default function ScrollWrapper({
width,
height,
children,
}: ScrollWrapperProps) {
return <div className={cn("overflow-auto", width, height)}>{children}</div>;
}
props
로 전달 받은 width, height는 cn
함수로 className에 추가되어 스타일링이 된다.
하지만 위와 같이 width와 height의 타입을 string으로 설정하면, 이 컴포넌트를 사용하는 입장에서 어떤 값을 전달해야 할지 잘 모를 수 있다.
ex) “w-10”
?, "10"
? 10px
?
그래서 tailwindest
라는 라이브러리를 이용하여 tailwind의 타입을 제공 받기로 했다.
import { type Tailwindest } from "tailwindest";
import { cn } from "@/lib/utils";
type ScrollWrapperProps = {
width?: Tailwindest["width"];
height?: Tailwindest["height"];
children: React.ReactNode;
};
export default function ScrollWrapper({
width,
height,
children,
}: ScrollWrapperProps) {
return <div className={cn("overflow-auto", width, height)}>{children}</div>;
}
이렇게 Tailwindest의 타입을 사용하면 아래와 같이 이 컴포넌트를 안전하게 사용할 수 있다.
⚓️ 사용자 피드백과 버그 기록
👷🏻 기술적 도전
📖 위키와 학습정리
✏️ 에디터
Novel이란?
Novel 스타일링 문제
에디터 저장 및 고려 사항들
📠 실시간 협업, 통신
Yorkie와 Novel editor 연동
YJS, Websocket, React-Flow
YJS, Socket.io
WebSocket과 Socket.io에 대해 간단히 알아보기
YJS 가이드 근데 이제 Socket.io를 곁들인
🏗️ 인프라와 CI/CD
NCloud CI CD 구축
BE 개발 스택과 기술적 고민
private key로 원격 서버 접근
nCloud 서버, VPC 만들고 설정
monorepo로 변경
⌛ 캐시, 최적화
rabbit mq 사용법
🔑 인증, 인가, 보안
passport로 oAuth 로그인 회원가입 구현
FE 로그인 기능 구현
JWT로 인증 인가 구현
JWT 쿠키로 사용하기
refresh token 보완하기
🧸 팀원 소개
⛺️ 그라운드 룰
🍞 커밋 컨벤션
🧈 이슈, PR 컨벤션
🥞 브랜치 전략
🌤️ 데일리 스크럼
📑 회의록
1️⃣ 1주차
킥오프(10/25)
2일차(10/29)
3일차(10/30)
4일차(10/31)
2️⃣ 2주차
8일차(11/04)
9일차(11/05)
11일차(11/07)
13일차(11/09)
3️⃣ 3주차
3주차 주간계획(11/11)
16일차(11/12)
18일차(11/14)
4️⃣ 4주차
4주차 주간계획(11/18)
23일차(11/19)
24일차(11/20)
25일차(11/21)
5️⃣ 5주차
5주차 주간계획(11/25)
29일차(11/25)
32일차(11/28)
34일차(11/30)
6️⃣ 6주차
6주차 주간계획(12/2)
37일차(12/3)