import { useStore } from '@tanstack/react-store' import { useRef } from 'react' import { replaceEqualDeep } from '@tanstack/router-core' import { isServer } from '@tanstack/router-core/isServer' import { useRouter } from './useRouter' import type { StructuralSharingOption, ValidateSelected, } from './structuralSharing' import type { AnyRouter, RegisteredRouter, RouterState, } from '@tanstack/router-core' export interface UseLocationBaseOptions< TRouter extends AnyRouter, TSelected, TStructuralSharing extends boolean = boolean, > { select?: ( state: RouterState['location'], ) => ValidateSelected } export type UseLocationResult< TRouter extends AnyRouter, TSelected, > = unknown extends TSelected ? RouterState['location'] : TSelected /** * Read the current location from the router state with optional selection. * Useful for subscribing to just the pieces of location you care about. * * Options: * - `select`: Project the `location` object to a derived value * - `structuralSharing`: Enable structural sharing for stable references * * @returns The current location (or selected value). * @link https://tanstack.com/router/latest/docs/framework/react/api/router/useLocationHook */ export function useLocation< TRouter extends AnyRouter = RegisteredRouter, TSelected = unknown, TStructuralSharing extends boolean = boolean, >( opts?: UseLocationBaseOptions & StructuralSharingOption, ): UseLocationResult { const router = useRouter() if (isServer ?? router.isServer) { const location = router.stores.location.get() return ( opts?.select ? opts.select(location as any) : location ) as UseLocationResult } const previousResult = // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static useRef>(undefined) // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static return useStore(router.stores.location, (location) => { const selected = ( opts?.select ? opts.select(location as any) : location ) as ValidateSelected if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) { const shared = replaceEqualDeep(previousResult.current, selected) previousResult.current = shared return shared } return selected }) as UseLocationResult }