diff --git a/src/hooks/useQueryState.ts b/src/hooks/useQueryState.ts index 361bf57..23212bc 100644 --- a/src/hooks/useQueryState.ts +++ b/src/hooks/useQueryState.ts @@ -1,64 +1,34 @@ -import { useState, useEffect } from 'react'; -import { useRouter } from 'next/router'; +import { useState, useEffect, useCallback } from 'react'; -type QueryValue = string | boolean | number; - -function useQueryState( - key: string, - defaultValue: T, - ignoreValues: QueryValue[] = [] -): [T, (newValue: T) => void] { - const router = useRouter(); - const [state, setState] = useState(() => { - const valueFromQuery = router.isReady ? router.query[key] : undefined; - return parseValue(valueFromQuery, defaultValue); +function useQueryState(key: string, defaultValue: string): [string, (value: string) => void] { + const [value, setValue] = useState(() => { + const params = new URLSearchParams(window.location.search); + return params.get(key) || defaultValue; }); - useEffect(() => { - if (!router.isReady) return; - const valueFromQuery = router.query[key]; - setState(parseValue(valueFromQuery, defaultValue)); - }, [router.isReady, router.query, key, defaultValue]); - - useEffect(() => { - const handleRouteChange = () => { - const valueFromQuery = router.query[key]; - setState(parseValue(valueFromQuery, defaultValue)); - }; - - router.events.on('routeChangeComplete', handleRouteChange); - return () => { - router.events.off('routeChangeComplete', handleRouteChange); - }; - }, [router.events, key, defaultValue]); - - const setQueryState = (newValue: T) => { - const newQuery = { ...router.query }; + const updateUrl = useCallback((newValue: string | null) => { + const url = new URL(window.location.href); + const params = new URLSearchParams(url.search); - if (ignoreValues.includes(newValue) || newValue === defaultValue) { - delete newQuery[key]; + if (newValue === defaultValue || newValue == null) { + params.delete(key); } else { - newQuery[key] = stringifyValue(newValue) as string; + params.set(key, newValue); } - router.push({ pathname: router.pathname, query: newQuery }, undefined, { shallow: true }); - setState(newValue); - }; + // 历史状态管理,避免生成新的历史记录条目 + window.history.replaceState({}, '', `${url.pathname}?${params}`); + }, [key, defaultValue]); - return [state, setQueryState]; -} - -function parseValue(value: string | string[] | undefined, defaultValue: T): T { - if (value === undefined || Array.isArray(value)) return defaultValue; - if (value === 'true') return true as T; - if (value === 'false') return false as T; - if (!isNaN(Number(value))) return Number(value) as T; - return value as unknown as T; -} + useEffect(() => { + if (value !== defaultValue) { + updateUrl(value); + } else { + updateUrl(null); // 传 null 以移除查询参数 + } + }, [value, updateUrl, defaultValue]); -function stringifyValue(value: QueryValue): string { - if (typeof value === 'boolean' || typeof value === 'number') return String(value); - return value as string; + return [value as string, setValue]; } export default useQueryState; diff --git a/src/slugs/trends/index.tsx b/src/slugs/trends/index.tsx index 33c59c2..58e8216 100644 --- a/src/slugs/trends/index.tsx +++ b/src/slugs/trends/index.tsx @@ -12,7 +12,7 @@ const MAX_COUNT = 5; export default function Trends({ manifest: pkg }: PageProps) { const [search, setSearch] = useState(''); - const [vs, setVS] = useQueryState('vs', ''); + const [vs, setVS] = useQueryState('vs', ''); const [pkgs, setPkgs] = useState(vs ? vs.split(',').slice(0, MAX_COUNT) : [pkg.name]); const { data: searchResult, isLoading } = useCachedSearch({ diff --git a/src/slugs/versions/index.tsx b/src/slugs/versions/index.tsx index 8f86534..8a592b3 100644 --- a/src/slugs/versions/index.tsx +++ b/src/slugs/versions/index.tsx @@ -48,7 +48,7 @@ const useStyles = createStyles(({ token, css }) => { function TagsList({ tagsInfo, pkg }: { tagsInfo: Record; pkg: PackageManifest }) { const { styles } = useStyles(); - const [type, setTags] = useQueryState('tags', 'prod', ['prod']); + const [type, setTags] = useQueryState('tags', 'prod'); const onlyProd = type === 'prod'; return (
@@ -71,7 +71,7 @@ function TagsList({ tagsInfo, pkg }: { tagsInfo: Record; pkg: }} > ; pkg: function VersionsList({ versions, pkg }: { versions: NpmPackageVersion[]; pkg: PackageManifest }) { const { styles } = useStyles(); - const [type, setVersions] = useQueryState('versions', 'prod', ['prod']); + const [type, setVersions] = useQueryState('versions', 'prod'); const onlyProd = type === 'prod'; return (
@@ -131,7 +131,7 @@ function VersionsList({ versions, pkg }: { versions: NpmPackageVersion[]; pkg: P }} >