|
1 | | -import { useEffect, useState } from 'react'; |
| 1 | +import { useEffect, useRef, useState } from 'react'; |
2 | 2 |
|
3 | | -const getHash = () => decodeURIComponent(window.location.hash.replace('#', '')); |
| 3 | +export const getHash = () => decodeURIComponent(window.location.hash.replace('#', '')); |
| 4 | + |
| 5 | +/** The use hash options type */ |
| 6 | +export interface UseHashOptions { |
| 7 | + /** The enabled state of the hook */ |
| 8 | + enabled?: boolean; |
| 9 | + /** The mode of hash setting */ |
| 10 | + mode?: 'initial' | 'replace'; |
| 11 | + /** Callback function called when hash changes */ |
| 12 | + onChange?: (hash: string) => void; |
| 13 | +} |
4 | 14 |
|
5 | 15 | /** The use hash return type */ |
6 | 16 | type UseHashReturn = [string, (value: string) => void]; |
7 | 17 |
|
| 18 | +export interface UseHash { |
| 19 | + (initialValue?: string, options?: UseHashOptions): UseHashReturn; |
| 20 | + |
| 21 | + (initialValue?: string, callback?: (hash: string) => void): UseHashReturn; |
| 22 | +} |
| 23 | + |
8 | 24 | /** |
9 | 25 | * @name useHash |
10 | 26 | * @description - Hook that manages the hash value |
11 | 27 | * @category State |
12 | 28 | * @usage low |
13 | 29 | * |
| 30 | + * @overload |
| 31 | + * @param {string} [initialValue] The initial hash value if no hash exists |
| 32 | + * @param {UseHashOptions} [options] Configuration options |
| 33 | + * @param {boolean} [options.enabled] The enabled state of the hook |
| 34 | + * @param {'initial' | 'replace'} [options.mode] The mode of hash setting |
| 35 | + * @param {(hash: string) => void} [options.onChange] Callback function called when hash changes |
| 36 | + * @returns {UseHashReturn} An array containing the hash value and a function to set the hash value |
| 37 | + * |
| 38 | + * @example |
| 39 | + * const [hash, setHash] = useHash("initial", { |
| 40 | + * enabled: true, |
| 41 | + * mode: "replace", |
| 42 | + * onChange: (newHash) => console.log('Hash changed:', newHash) |
| 43 | + * }); |
| 44 | + * |
| 45 | + * @overload |
14 | 46 | * @param {string} [initialValue] The initial hash value if no hash exists |
| 47 | + * @param {(hash: string) => void} [callback] Callback function called when hash changes |
15 | 48 | * @returns {UseHashReturn} An array containing the hash value and a function to set the hash value |
16 | 49 | * |
17 | 50 | * @example |
18 | | - * const [hash, setHash] = useHash("initial"); |
| 51 | + * const [hash, setHash] = useHash("initial", (newHash) => console.log('Hash changed:', newHash)); |
19 | 52 | */ |
20 | | -export const useHash = ( |
21 | | - initialValue = '', |
22 | | - mode: 'initial' | 'replace' = 'replace' |
23 | | -): UseHashReturn => { |
| 53 | +export const useHash = ((...params: any[]) => { |
| 54 | + const [initialValue = '', param] = params; |
| 55 | + |
| 56 | + const options = (typeof param === 'function' ? { onChange: param } : param) as |
| 57 | + | UseHashOptions |
| 58 | + | undefined; |
| 59 | + |
| 60 | + const enabled = options?.enabled ?? true; |
| 61 | + const mode = options?.mode ?? 'replace'; |
| 62 | + |
24 | 63 | const [hash, setHash] = useState(() => { |
25 | 64 | if (typeof window === 'undefined') return initialValue; |
26 | 65 | return getHash() || initialValue; |
27 | 66 | }); |
28 | 67 |
|
| 68 | + const optionsRef = useRef(options); |
| 69 | + optionsRef.current = options; |
| 70 | + |
29 | 71 | const set = (value: string) => { |
30 | 72 | window.location.hash = value; |
31 | 73 | setHash(value); |
| 74 | + optionsRef.current?.onChange?.(value); |
32 | 75 | }; |
33 | 76 |
|
34 | 77 | useEffect(() => { |
| 78 | + if (!enabled) return; |
| 79 | + |
35 | 80 | if (mode === 'replace') window.location.hash = hash; |
36 | 81 |
|
37 | | - const onHashChange = () => setHash(getHash()); |
| 82 | + const onHashChange = () => { |
| 83 | + const newHash = getHash(); |
| 84 | + setHash(newHash); |
| 85 | + optionsRef.current?.onChange?.(newHash); |
| 86 | + }; |
| 87 | + |
38 | 88 | window.addEventListener('hashchange', onHashChange); |
39 | 89 | return () => { |
40 | 90 | window.removeEventListener('hashchange', onHashChange); |
41 | 91 | }; |
42 | | - }, []); |
| 92 | + }, [enabled, mode]); |
43 | 93 |
|
44 | 94 | return [hash, set] as const; |
45 | | -}; |
| 95 | +}) as UseHash; |
0 commit comments