useParams.ts65 lines · main
1/*
2 * next/compat/router is used so that this doesn't cause an error on App
3 * Router builds. However, no replacement for the functionality is provided if
4 * the router is missing (it just silently fails).
5 *
6 * This is fine because docs (the only site moving to App Router right now)
7 * doesn't use this hook. Skipping it silently is less troublesome than trying
8 * to make it work across both routers -- making search params work seamlessly
9 * is a giant pain, and too much critical studio functionality depends on this
10 * to mess with it lightly.
11 */
12import { useRouter } from 'next/compat/router'
13import { useMemo } from 'react'
14
15/**
16 * Helper to convert kebab case to camel case
17 */
18function convertToCamelCase(key: string): string {
19 if (!key.includes('-')) {
20 return key
21 }
22
23 const parts = key.split('-')
24 const capitalizedParts = parts.map((part, index) => {
25 if (index === 0) {
26 return part
27 }
28 return part.charAt(0).toUpperCase() + part.slice(1)
29 })
30 return capitalizedParts.join('')
31}
32
33export function useParams(): {
34 [k: string]: string | undefined
35} {
36 const router = useRouter()
37 const query = router?.query
38
39 const modifiedQuery = {
40 ...query,
41 }
42
43 // Convert kebab case keys to camel case
44 Object.keys(modifiedQuery).forEach((key) => {
45 const modifiedKey = convertToCamelCase(key)
46 if (modifiedKey !== key) {
47 modifiedQuery[modifiedKey] = modifiedQuery[key]
48 delete modifiedQuery[key]
49 }
50 })
51
52 return useMemo(
53 () =>
54 Object.fromEntries(
55 Object.entries(modifiedQuery).map(([key, value]) => {
56 if (Array.isArray(value)) {
57 return [key, value[0]]
58 } else {
59 return [key, value]
60 }
61 })
62 ),
63 [query]
64 )
65}