URL 쿼리 스트링과 React 리액트 상태 관리의 만남: `nuqs` 사용법 가이드

URL 쿼리 스트링과 React 리액트 상태 관리의 만남: nuqs 사용법 가이드

안녕하세요!

 

오늘은 React 애플리케이션에서 URL 쿼리 스트링을 활용해 상태를 관리할 수 있게 도와주는 nuqs라는 라이브러리를 소개하겠습니다.

 

nuqs는 간단하고 타입 안전하며, Next.js, React Router, Remix 등 다양한 React 기반 프레임워크와 함께 사용할 수 있습니다.

 

이 글은 튜토리얼 형식으로 작성되었으니, 단계별로 따라 하면서 nuqs의 매력을 체험해 보세요!


1️⃣ 시작하기: nuqs 설치

먼저 nuqs를 설치해야 합니다.

 

프로젝트 루트 디렉토리에서 다음 명령어 중 하나를 실행하세요.

# npm
npm install nuqs

# yarn
yarn add nuqs

# pnpm
pnpm add nuqs

 

설치가 완료되었다면 준비 완료입니다! 이제 본격적으로 nuqs를 사용해 보겠습니다.


2️⃣ 기본 사용법: useQueryState

nuqs의 핵심은 useQueryState라는 훅입니다.

 

이 훅을 사용하면 URL 쿼리 스트링을 마치 useState처럼 쉽게 다룰 수 있습니다.

 

다음은 간단한 예제입니다. URL 쿼리 스트링에 name 값을 저장하고 읽는 애플리케이션을 만들어 보겠습니다.

예제 코드

'use client'

import { useQueryState } from 'nuqs'

export default function App() {
  const [name, setName] = useQueryState('name') // 쿼리 키: 'name'

  return (
    <div style={{ padding: '20px' }}>
      <h1>안녕하세요, {name || '방문자'}님!</h1>
      <input
        type="text"
        value={name || ''}
        onChange={(e) => setName(e.target.value)}
        placeholder="이름을 입력하세요"
      />
      <button onClick={() => setName(null)}>초기화</button>
    </div>
  )
}

결과 확인

  1. 애플리케이션을 실행한 후 브라우저에서 확인하세요.
  2. 입력 필드에 이름을 입력하면 URL이 자동으로 업데이트됩니다. 예: http://localhost:3000/?name=John
  3. "초기화" 버튼을 클릭하면 URL에서 name 값이 제거됩니다.

3️⃣ 숫자, 날짜, 배열 등 다양한 타입 처리하기

nuqs는 문자열뿐만 아니라 숫자, 날짜, 배열 등 다양한 타입을 처리할 수 있도록 파서(parser)를 제공합니다.

 

아래 예제에서 숫자와 배열을 다루는 방법을 알아봅시다.

숫자와 배열 다루기

'use client'

import { useQueryState, parseAsInteger, parseAsArrayOf } from 'nuqs'

export default function App() {
  const [count, setCount] = useQueryState('count', parseAsInteger.withDefault(0)) // 기본값: 0
  const [tags, setTags] = useQueryState('tags', parseAsArrayOf((v) => v)) // 문자열 배열

  return (
    <div style={{ padding: '20px' }}>
      <h1>카운트: {count}</h1>
      <button onClick={() => setCount((c) => c + 1)}>+1</button>
      <button onClick={() => setCount((c) => c - 1)}>-1</button>
      <button onClick={() => setCount(null)}>초기화</button>

      <h2>태그</h2>
      <input
        type="text"
        placeholder="태그를 콤마(,)로 구분하여 입력하세요"
        onBlur={(e) => setTags(e.target.value.split(','))}
      />
      <p>입력한 태그: {tags?.join(', ') || '없음'}</p>
      <button onClick={() => setTags(null)}>태그 초기화</button>
    </div>
  )
}

주요 기능 설명:

  • parseAsInteger: 쿼리 값을 숫자로 변환합니다. 기본값(withDefault)을 설정하면 URL에 값이 없을 때 기본값을 반환합니다.
  • parseAsArrayOf: 배열 값을 처리합니다. 위 코드에서는 입력된 문자열을 콤마로 나눠 배열로 변환했습니다.

결과

  1. 카운트 버튼을 클릭하면 URL에 count 값이 업데이트됩니다.
    1. 예: http://localhost:3000/?count=5
  2. 태그를 입력하고 URL에 반영된 결과를 확인하세요.
    1. 예: http://localhost:3000/?tags=React,Next.js,JavaScript

4️⃣ 여러 상태를 한 번에 관리하기: useQueryStates

useQueryStates를 사용하면 여러 상태를 객체 형태로 묶어 관리할 수 있습니다.

 

예를 들어, 좌표값(lat, lng)을 동시에 처리하려면 다음과 같이 작성할 수 있습니다.

좌표값 관리하기

'use client'

import { useQueryStates, parseAsFloat } from 'nuqs'

export default function App() {
  const [coordinates, setCoordinates] = useQueryStates({
    lat: parseAsFloat.withDefault(37.5665), // 기본값: 서울 위도
    lng: parseAsFloat.withDefault(126.9780) // 기본값: 서울 경도
  })

  const updateCoordinates = () => {
    setCoordinates({
      lat: Math.random() * 180 - 90, // 위도: -90 ~ 90
      lng: Math.random() * 360 - 180 // 경도: -180 ~ 180
    })
  }

  return (
    <div style={{ padding: '20px' }}>
      <h1>현재 좌표</h1>
      <p>위도: {coordinates.lat}</p>
      <p>경도: {coordinates.lng}</p>
      <button onClick={updateCoordinates}>무작위 좌표 생성</button>
      <button onClick={() => setCoordinates(null)}>초기화</button>
    </div>
  )
}

결과

  1. "무작위 좌표 생성" 버튼을 클릭하면 URL에 새로운 latlng 값이 반영됩니다.
  2. URL 예: http://localhost:3000/?lat=12.3456&lng=78.9101
  3. "초기화" 버튼을 클릭하면 좌표값이 기본값으로 초기화됩니다.

5️⃣ Next.js에서의 사용법

nuqs는 Next.js의 pagesapp 라우터를 모두 지원합니다.

 

Next.js 앱에서 nuqs를 사용하려면 NuqsAdapter를 프로젝트의 최상위 컴포넌트(예: _app.tsx 또는 layout.tsx)에 추가해야 합니다.

NuqsAdapter 설정

App Router (layout.tsx)

import { NuqsAdapter } from 'nuqs/adapters/next/app'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <NuqsAdapter>{children}</NuqsAdapter>
      </body>
    </html>
  )
}

Pages Router (_app.tsx)

import { NuqsAdapter } from 'nuqs/adapters/next/pages'

export default function MyApp({ Component, pageProps }) {
  return (
    <NuqsAdapter>
      <Component {...pageProps} />
    </NuqsAdapter>
  )
}

6️⃣ 고급 기능: 사용자 정의 파서

nuqs는 기본 제공 파서 외에 사용자 정의 파서를 지원합니다.

 

예를 들어, 16진수 색상 값을 처리하려면 다음과 같이 작성할 수 있습니다.

import { useQueryState, createParser } from 'nuqs'

const hexColorParser = createParser({
  parse: (query) => `#${query}`, // URL 쿼리를 16진수 색상으로 변환
  serialize: (value) => value.replace('#', '') // '#RRGGBB' → 'RRGGBB'
})

export default function App() {
  const [color, setColor] = useQueryState('color', hexColorParser.withDefault('#000000'))

  return (
    <div style={{ backgroundColor: color, padding: '20px', color: '#fff' }}>
      <h1>현재 색상: {color}</h1>
      <button onClick={() => setColor('#ff0000')}>빨강</button>
      <button onClick={() => setColor('#00ff00')}>초록</button>
      <button onClick={() => setColor('#0000ff')}>파랑</button>
    </div>
  )
}

결론

nuqs를 사용하면 URL 쿼리 스트링을 통해 상태를 관리하면서도 React의 상태 관리 방식을 그대로 유지할 수 있습니다.

 

이 라이브러리는 특히 Next.js와 같은 서버-클라이언트 통합 프레임워크에서 강력한 도구로 활용될 수 있습니다.

 

여러분도 프로젝트에서 nuqs를 사용해 보세요. URL 기반으로 상태를 관리하는 새로운 패러다임을 경험할 수 있을 것입니다.

더 자세한 내용은 공식 문서를 참고하세요.