728x90

Tailwind Breakpoint 기준으로 useResponsive 훅 만들기
Tailwind 반응형 클래스
http://tailwindcss.com/docs/responsive-design
Responsive design - Core concepts
Using responsive utility variants to build adaptive user interfaces.
tailwindcss.com
나는 평소에 반응형 작업을 할 때
Tailwind의 sm, md, lg 같은 breakpoint 클래스를 사용했다.
<div className="hidden md:block">
PC에서만 보이는 요소
</div>
이 방식은 스타일 제어에는 정말 편하다.
하지만 다음과 같은 상황에서는 한계가 있었다.
- 모바일일 때 아예 컴포넌트를 렌더링하지 않고 싶을 때
- 특정 디바이스에서 API 호출을 막고 싶을 때
- 조건부 로직 분기가 필요할 때
- JSX 레벨에서 완전히 다른 구조를 렌더링해야 할 때
👉 이때는 className이 아니라 "변수"가 필요했다.
그래서 만든 useResponsive 커스텀 훅
나는 react-responsive의 useMediaQuery를 사용해서
디바이스 타입을 boolean 값으로 반환하는 훅을 만들었다.
import { useMediaQuery } from 'react-responsive'
import { useState, useEffect } from 'react'
export const useResponsive = () => {
const [isMounted, setIsMounted] = useState(false)
useEffect(() => {
setIsMounted(true)
}, [])
// Tailwind Default Breakpoints 기준
const isMobile = useMediaQuery({ maxWidth: 639 })
const isTablet = useMediaQuery({ minWidth: 640, maxWidth: 1023 })
const isPc = useMediaQuery({ minWidth: 1024 })
if (!isMounted) {
return { isMobile: false, isTablet: false, isPc: false }
}
return { isMobile, isTablet, isPc }
}
왜 isMounted 처리를 해야 할까?
Next.js 환경에서는 SSR(Server Side Rendering) 때문에 초기 렌더링 시점에 window 객체가 존재하지 않는다.
useMediaQuery는 브라우저 환경에서 동작하기 때문에 hydration mismatch 오류가 발생할 수 있다.
그래서
const [isMounted, setIsMounted] = useState(false)
useEffect(() => {
setIsMounted(true)
}, [])
마운트 이후에만 값을 반환하도록 처리했다.
👉 이렇게 하면 hydration 오류를 방지할 수 있다.
실제 사용 예시
- 아예 렌더링을 막고 싶을 때
const { isMobile } = useResponsive()
if (isMobile) return null
모바일에서는 컴포넌트를 완전히 렌더링하지 않는다.
- 조건부 API 호출
useEffect(() => {
if (isPc) {
fetchLargeData()
}
}, [isPc])
PC에서만 무거운 데이터를 불러올 수 있다.
- JSX 구조 자체를 다르게 렌더링
return (
<>
{isMobile ? <MobileLayout /> : <DesktopLayout />}
</>
)
Tailwind로는 해결할 수 없는 구조 분기가 가능하다.
스타일 반응형은 Tailwind로,
렌더링/로직 반응형은 커스텀 훅으로 분리하자!!!
'✨FRONTEND > 📍React' 카테고리의 다른 글
| dnd-kit로 칸반보드 구현하기 (@dnd-kit/react) (0) | 2026.03.24 |
|---|---|
| React/Next.js 마크다운 목차 구현하기 (feat. 클릭 시 스크롤) (0) | 2026.03.16 |
| 패키지 관리자 비교 (0) | 2026.02.13 |
| shadcn/ui: 도입부터 커스텀까지 (0) | 2026.02.06 |
| React에서 map 쓰는 패턴 정리 (0) | 2025.12.02 |