nuqs๋Š” Next.js์—์„œ URL ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ƒํƒœ์ฒ˜๋Ÿผ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.

์˜ค๋Š˜์€ 'nuqs'์˜ useQueryState์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฒƒ์ด๋‹ค.

 

 

๊ธฐ๋ณธ ๊ฐœ๋…

useQueryState๋Š” React์˜ useState์™€ ๋น„์Šทํ•˜๊ฒŒ ๋™์ž‘ํ•˜์ง€๋งŒ, ์ƒํƒœ๋ฅผ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€๊ฐ€ ์•„๋‹Œ URL ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

 

import { useQueryState } from 'nuqs'

function SearchComponent() {
  const [search, setSearch] = useQueryState('search')
  
  // URL: /?search=hello
  // search ๊ฐ’: "hello"
  
  return (
    <input 
      value={search || ''} 
      onChange={(e) => setSearch(e.target.value)}
    />
  )
}

 

์ฃผ์š” ํŠน์ง•

URL๊ณผ ์ž๋™ ๋™๊ธฐํ™”

  • ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด URL์ด ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค
  • ๋’ค๋กœ๊ฐ€๊ธฐ/์•ž์œผ๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ์ด ์ •์ƒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค
  • URL์„ ๊ณต์œ ํ•˜๋ฉด ๊ฐ™์€ ์ƒํƒœ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

ํƒ€์ž… ์•ˆ์ „์„ฑ

  • ํŒŒ์„œ(parser)๋ฅผ ์‚ฌ์šฉํ•ด ํƒ€์ž…์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
import { useQueryState, parseAsInteger, parseAsBoolean } from 'nuqs'

const [page, setPage] = useQueryState('page', parseAsInteger.withDefault(1))
const [isActive, setIsActive] = useQueryState('active', parseAsBoolean)

 

 

๊ธฐ๋ณธ๊ฐ’ ์„ค์ •

const [sort, setSort] = useQueryState('sort', { defaultValue: 'name' })

 

 

์—ฌ๋Ÿฌ ํŒŒ๋ผ๋ฏธํ„ฐ ๋™์‹œ ๊ด€๋ฆฌ

import { useQueryStates } from 'nuqs'

const [filters, setFilters] = useQueryStates({
  search: parseAsString,
  page: parseAsInteger.withDefault(1),
  category: parseAsString
})

// ์—ฌ๋Ÿฌ ๊ฐ’์„ ํ•œ ๋ฒˆ์— ์—…๋ฐ์ดํŠธ
setFilters({ search: 'test', page: 1 })

 

 

์‹ค์ œ ์‚ฌ์šฉ ์˜ˆ์‹œ

๊ฒ€์ƒ‰๊ณผ ํ•„ํ„ฐ๋ง์ด ์žˆ๋Š” ์ƒํ’ˆ ๋ชฉ๋ก:

function ProductList() {
  const [search, setSearch] = useQueryState('search')
  const [category, setCategory] = useQueryState('category')
  const [page, setPage] = useQueryState('page', parseAsInteger.withDefault(1))

  return (
    <div>
      <input 
        value={search || ''} 
        onChange={(e) => setSearch(e.target.value)}
        placeholder="๊ฒ€์ƒ‰..."
      />
      
      <select 
        value={category || ''} 
        onChange={(e) => setCategory(e.target.value)}
      >
        <option value="">์ „์ฒด</option>
        <option value="electronics">์ „์ž์ œํ’ˆ</option>
        <option value="clothing">์˜๋ฅ˜</option>
      </select>
      
      {/* URL: /?search=laptop&category=electronics&page=2 */}
    </div>
  )
}

 

 

์žฅ์ 

  • SEO ์นœํ™”์ : ํ•„ํ„ฐ๋ง๋œ ์ƒํƒœ๊ฐ€ URL์— ์žˆ์–ด ํฌ๋กค๋Ÿฌ๊ฐ€ ์ธ๋ฑ์‹ฑ ๊ฐ€๋Šฅ
  • ๊ณต์œ  ๊ฐ€๋Šฅ: URL๋งŒ์œผ๋กœ ์ •ํ™•ํ•œ ํŽ˜์ด์ง€ ์ƒํƒœ ๊ณต์œ 
  • ์ƒˆ๋กœ๊ณ ์นจ ์•ˆ์ „: ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•ด๋„ ์ƒํƒœ ์œ ์ง€
  • ๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ: ๋’ค๋กœ๊ฐ€๊ธฐ/์•ž์œผ๋กœ๊ฐ€๊ธฐ ์ง€์›

Next.js์˜ App Router์™€ Pages Router ๋ชจ๋‘์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํŠนํžˆ ๊ฒ€์ƒ‰, ํ•„ํ„ฐ๋ง, ํŽ˜์ด์ง€๋„ค์ด์…˜ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๋•Œ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

 

+ Recent posts