쿼리 파라미터를 쉽게 사용하게 해주는 nuqs 써보기

vite로 만든 react-ts 프로젝트 상에서 진행했다.

설치와 설정 #

npm install nuqs

nuqs 사용을 위해서는 NuqsAdapter 컨텍스트 프로바이더가 필요하다. 나같은 React spa의 경우 이렇게. 다른 프레임워크들의 경우 문서 참고

import { NuqsAdapter } from 'nuqs/adapters/react'

createRoot(document.getElementById('root')!).render(
  <NuqsAdapter>
    <App />
  </NuqsAdapter>
)

기본 사용 #

useState 대신 useQueryState 사용하면 알아서 URL이랑 싱크됨.

const [name, setName] = useQueryState("name");

이때 useQueryState가 받는 하나의 인자는 쿼리스트링의 key다. query string state랑 updater function을 리턴한다.

해당 key의 쿼리스트링 값이 없으면(/이면) state 값은 null. 비어 있으면 빈 문자열이다.

/?name=3 과 같은 경우 state는 '3'이다. 쿼리 값은 기본적으로 문자열임. 이걸 바꾸려면 parser 사용

const [count, setCount] = useQueryState("count", parseAsInteger);

useState의 인자는 기본값인데 useQueryState는 query key가 인자라는 게 차이점. useQueryState 2번째 인자로 option을 넣을 수 있는데 여기 defaultValue로 기본값 지정 가능

const [name, setName] = useQueryState("name", { defaultValue: "홍길동" });

parser가 있을 경우 .withDefault(value) 빌더 메서드 사용. 이렇게 기본값을 지정했을 경우 이 기본값은 default 설정상에서는 URL에 포함되지 않는다. 이걸 만약 포함하고 싶다면 clearOnDefault 옵션 사용

// parser 미사용 시
const [name, setName] = useQueryState("name", {
  defaultValue: "홍길동",
  clearOnDefault: false,
});

// parser 사용 시
const [count, setCount] = useQueryState(
  "count",
  parseAsInteger.withDefault(0).withOptions({ clearOnDefault: false })
);

이 기본값은 쿼리스트링 값이 파서에게 유효하지 않을 때도 적용된다.

파서 #

search param은 기본적으로 문자열이지만 숫자, 불리언, 배열 등으로 다룰 수 있다. nuqs는 몇 가지 기본 파서를 제공한다.

export const searchParamsParsers = {
  q: parseAsString.withDefault("").withOptions({
    shallow: false,
  }),
};

리터럴로 파싱하기

const sortOrder = ['asc', 'desc'] as const
// Then pass it to the parser
parseAsStringLiteral(sortOrder)

// 숫자로도 가능
const diceSides = [1, 2, 3, 4, 5, 6] as const

parseAsNumberLiteral(diceSides)

// enum도 지원

enum Color {
  Red = 'red',
  Green = 'green',
  Blue = 'blue',
}
parseAsStringEnum(Object.values(Color))

이외의 DateTime, Array, JSON 파서들도 제공된다. 문서 참고

커스텀 파서를 직접 만들 수도 있다. 필요할 때 써보자. https://nuqs.dev/docs/parsers/making-your-own

기본 옵션

const [{ latitude, longitude }, setCoordinates] = useQueryStates(
  {
    latitude: parseAsFloat,
    longitude: parseAsFloat,
  },
  {
    urlKeys: {
      latitude: "lat", // URL에는 ?lat=... 로 표시
      longitude: "lng",
    },
  }
);