import { useMatches, useRouteError } from 'react-router-dom'; import { parseQuery } from './query'; export function usePrevious(value: T): T | null { const ref = useRef(null); useEffect(() => { ref.current = value; }, [value]); return ref.current; } function getCatchAllParam(str: string | undefined) { if (!str) return null; // \[\.\.\.(\w+)\] 用来匹配形如 [...slug] // (\w+) 意味着捕获“字母、数字或下划线”组成的部分 const match = str.match(/\[\.\.\.(\w+)\]/); return match ? match[1] : null; } function getParams( params: Record | undefined, id: string ): Record | undefined { if (!params?.['*']) return params; const lastName = id.split('_').at(-1); const catchAllParam = getCatchAllParam(lastName); if (catchAllParam) { return { [catchAllParam]: params['*'].split('/') }; } return params; } /** - get route meta */ export function useRoute< T = unknown, Q extends Record | null = Record, P extends Record = Record >() { const matches = useMatches(); const routes = matches.at(-1) as Router.Route; const { hash, pathname, search } = useLocation(); const fullPath = pathname + search + hash; const query = parseQuery(search) as Q; const error = useRouteError() as Error | null; return useMemo( () => ({ ...routes, error, fullPath, hash, matched: matches.slice(1) as Router.Route[], params: getParams(routes.params as Record, routes.id) as P, pathname, query, redirect: null, search }) as Router.Route, [fullPath] ); } export function usePreviousRoute() { return useOutletContext(); }