useAppsQueryState.ts 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. import { type ReadonlyURLSearchParams, usePathname, useRouter, useSearchParams } from 'next/navigation'
  2. import { useCallback, useEffect, useMemo, useState } from 'react'
  3. type AppsQuery = {
  4. tagIDs?: string[]
  5. keywords?: string
  6. creator?: string
  7. isCreatedByMe?: boolean
  8. }
  9. // Parse the query parameters from the URL search string.
  10. function parseParams(params: ReadonlyURLSearchParams): AppsQuery {
  11. const tagIDs = params.get('tagIDs')?.split(';')
  12. const keywords = params.get('keywords') || undefined
  13. const isCreatedByMe = params.get('isCreatedByMe') === 'true'
  14. return { tagIDs, keywords, isCreatedByMe }
  15. }
  16. // Update the URL search string with the given query parameters.
  17. function updateSearchParams(query: AppsQuery, current: URLSearchParams) {
  18. const { tagIDs, keywords, isCreatedByMe } = query || {}
  19. if (tagIDs && tagIDs.length > 0)
  20. current.set('tagIDs', tagIDs.join(';'))
  21. else
  22. current.delete('tagIDs')
  23. if (keywords)
  24. current.set('keywords', keywords)
  25. else
  26. current.delete('keywords')
  27. if (isCreatedByMe)
  28. current.set('isCreatedByMe', 'true')
  29. else
  30. current.delete('isCreatedByMe')
  31. }
  32. function useAppsQueryState() {
  33. const searchParams = useSearchParams()
  34. const [query, setQuery] = useState<AppsQuery>(() => parseParams(searchParams))
  35. const router = useRouter()
  36. const pathname = usePathname()
  37. const syncSearchParams = useCallback((params: URLSearchParams) => {
  38. const search = params.toString()
  39. const query = search ? `?${search}` : ''
  40. router.push(`${pathname}${query}`, { scroll: false })
  41. }, [router, pathname])
  42. // Update the URL search string whenever the query changes.
  43. useEffect(() => {
  44. const params = new URLSearchParams(searchParams)
  45. updateSearchParams(query, params)
  46. syncSearchParams(params)
  47. }, [query, searchParams, syncSearchParams])
  48. return useMemo(() => ({ query, setQuery }), [query])
  49. }
  50. export default useAppsQueryState