Skip to content

Commit

Permalink
refactor: version switch
Browse files Browse the repository at this point in the history
  • Loading branch information
elrrrrrrr committed Jun 7, 2024
1 parent 449c395 commit 018e6e4
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 57 deletions.
74 changes: 22 additions & 52 deletions src/hooks/useQueryState.ts
Original file line number Diff line number Diff line change
@@ -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<T extends QueryValue>(
key: string,
defaultValue: T,
ignoreValues: QueryValue[] = []
): [T, (newValue: T) => void] {
const router = useRouter();
const [state, setState] = useState<T>(() => {
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<T extends QueryValue>(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;
2 changes: 1 addition & 1 deletion src/slugs/trends/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const MAX_COUNT = 5;

export default function Trends({ manifest: pkg }: PageProps) {
const [search, setSearch] = useState('');
const [vs, setVS] = useQueryState<string>('vs', '');
const [vs, setVS] = useQueryState('vs', '');
const [pkgs, setPkgs] = useState<string[]>(vs ? vs.split(',').slice(0, MAX_COUNT) : [pkg.name]);

const { data: searchResult, isLoading } = useCachedSearch({
Expand Down
8 changes: 4 additions & 4 deletions src/slugs/versions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const useStyles = createStyles(({ token, css }) => {

function TagsList({ tagsInfo, pkg }: { tagsInfo: Record<string, string[]>; pkg: PackageManifest }) {
const { styles } = useStyles();
const [type, setTags] = useQueryState<string>('tags', 'prod', ['prod']);
const [type, setTags] = useQueryState('tags', 'prod');
const onlyProd = type === 'prod';
return (
<div style={{ position: 'relative' }}>
Expand All @@ -71,7 +71,7 @@ function TagsList({ tagsInfo, pkg }: { tagsInfo: Record<string, string[]>; pkg:
}}
>
<Segmented
defaultValue={type || 'prod'}
value={type}
options={[
{ label: '正式版本', value: 'prod' },
{ label: '所有版本', value: 'all' },
Expand Down Expand Up @@ -108,7 +108,7 @@ function TagsList({ tagsInfo, pkg }: { tagsInfo: Record<string, string[]>; pkg:

function VersionsList({ versions, pkg }: { versions: NpmPackageVersion[]; pkg: PackageManifest }) {
const { styles } = useStyles();
const [type, setVersions] = useQueryState<string>('versions', 'prod', ['prod']);
const [type, setVersions] = useQueryState('versions', 'prod');
const onlyProd = type === 'prod';
return (
<div style={{ position: 'relative' }}>
Expand All @@ -131,7 +131,7 @@ function VersionsList({ versions, pkg }: { versions: NpmPackageVersion[]; pkg: P
}}
>
<Segmented
defaultValue={type || 'prod'}
value={type}
options={[
{ label: '正式版本', value: 'prod' },
{ label: '所有版本', value: 'all' },
Expand Down

0 comments on commit 018e6e4

Please sign in to comment.