useQueryStates

如何同时读取和更新多个搜索参数

多个更新(批处理)

您可以在单个事件循环 tick 中调用任意数量的状态更新函数,它们将异步应用于 URL:

const MultipleQueriesDemo = () => {
  const [lat, setLat] = useQueryState('lat', parseAsFloat)
  const [lng, setLng] = useQueryState('lng', parseAsFloat)
  const randomCoordinates = React.useCallback(() => {
    setLat(Math.random() * 180 - 90)
    setLng(Math.random() * 360 - 180)
  }, [])
}

如果您希望知道 URL 何时被更新以及它包含什么内容,可以等待状态更新函数返回的 Promise,它将为您提供更新的 URLSearchParameters 对象:

const randomCoordinates = React.useCallback(() => {
  setLat(42)
  return setLng(12)
}, [])

randomCoordinates().then((search: URLSearchParams) => {
  search.get('lat') // 42
  search.get('lng') // 12, 已排队并批处理更新
})
实现细节(Promise 缓存)

返回的 Promise 会被缓存直到下一次刷新到 URL 时发生, 因此在同一事件循环 tick 中对任何钩子的 setState 调用将返回相同的 Promise 引用。

由于对 Web History API 的调用被节流,Promise 可能被缓存几个 tick。批处理更新将被合并并一次性刷新到 URL。 这意味着并非每个 setState 都会反映到 URL 中,如果在刷新发生前有另一个覆盖它的调用。

返回的 React 状态将立即反映所有设置的值, 以保持 UI 响应性。


useQueryStates

对于应该始终一起移动的查询键,您可以使用 useQueryStates 并带有一个包含每个键类型的对象:

import { useQueryStates, parseAsFloat } from 'nuqs'

const [coordinates, setCoordinates] = useQueryStates(
  {
    lat: parseAsFloat.withDefault(45.18),
    lng: parseAsFloat.withDefault(5.72)
  },
  {
    history: 'push'
  }
)

const { lat, lng } = coordinates

// 一次设置所有键(或子集):
const search = await setCoordinates({
  lat: Math.random() * 180 - 90,
  lng: Math.random() * 360 - 180
})

选项

useQueryStates 中,您可以在三个地方定义选项

  • 作为钩子本身的第二个参数(全局选项,如上面的 history: 'push'
  • 在每个解析器上,如 parseAsFloat.withOptions({ shallow: false })
  • 在更新状态时的调用级别:
setCoordinates(
  {
    lat: 42,
    lng: 12
  },
  {
    shallow: false
  }
)

优先级顺序是:调用级别选项 > 解析器选项 > 全局选项。

提示

您可以通过将 null 传递给状态更新函数来清除由 useQueryStates 钩子管理的所有键:

const clearAll = () => setCoordinates(null)

这将清除 latlng,并保留其他搜索参数不变。

更短的搜索参数键

Introduced in version 1.20.0.

将解析器对象键绑定到搜索参数键的一个问题是,您必须在适合您领域或业务逻辑的变量名和短小的、URL 友好的键之间进行权衡。

您可以在钩子选项中使用 urlKeys 对象 来将变量名重新映射到更短的键:

const [{ latitude, longitude }, setCoordinates] = useQueryStates(
  {
    // 在您的代码库中使用有意义的变量名
    latitude: parseAsFloat.withDefault(45.18),
    longitude: parseAsFloat.withDefault(5.72)
  },
  {
    urlKeys: {
      // 并将它们重新映射到 URL 中的更短键
      latitude: 'lat',
      longitude: 'lng'
    }
  }
)

// 设置器 API 无变化,但键被重新映射为:
// ?lat=45.18&lng=5.72
setCoordinates({
  latitude: 45.18,
  longitude: 5.72
})

随着您的应用程序增长,您可能希望在多个组件或 nuqs 功能中重用这些解析器和 urlKeys 定义(如加载器序列化器)。

您可以使用 UrlKeys 类型助手来实现这一点:

import { type UrlKeys } from 'nuqs' // or 'nuqs/server'

export const coordinatesParsers = {
  latitude: parseAsFloat.withDefault(45.18),
  longitude: parseAsFloat.withDefault(5.72)
}

export const coordinatesUrlKeys: UrlKeys<typeof coordinatesParsers> = {
  latitude: 'lat',
  longitude: 'lng'
}
Introduced in version 2.3.0.