UNPKG

@tanstack/vue-router

Version:

Modern and scalable routing for Vue applications

78 lines 3.58 kB
import * as Vue from 'vue'; import { invariant } from '@tanstack/router-core'; import { useStore } from '@tanstack/vue-store'; import { isServer } from '@tanstack/router-core/isServer'; import { injectDummyPendingMatch, injectPendingMatch, routeIdContext, } from './matchContext'; import { useRouter } from './useRouter'; export function useMatch(opts) { const router = useRouter(); // During SSR we render exactly once and do not need reactivity. // Avoid store subscriptions and pending/transition bookkeeping on the server. if (isServer ?? router.isServer) { const nearestRouteId = opts.from ? undefined : Vue.inject(routeIdContext); const matchStore = (opts.from ?? nearestRouteId) ? router.stores.getRouteMatchStore(opts.from ?? nearestRouteId) : undefined; const match = matchStore?.get(); if ((opts.shouldThrow ?? true) && !match) { if (process.env.NODE_ENV !== 'production') { throw new Error(`Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`); } invariant(); } if (match === undefined) { return Vue.ref(undefined); } return Vue.ref(opts.select ? opts.select(match) : match); } const hasPendingNearestMatch = opts.from ? injectDummyPendingMatch() : injectPendingMatch(); // Set up reactive match value based on lookup strategy. let match; if (opts.from) { // routeId case: single subscription via per-routeId computed store. // The store reference is stable (cached by routeId). const matchStore = router.stores.getRouteMatchStore(opts.from); match = useStore(matchStore, (value) => value); } else { // matchId case: use routeId from context for stable store lookup. // The routeId is provided by the nearest Match component and doesn't // change for the component's lifetime, so the store is stable. const nearestRouteId = Vue.inject(routeIdContext); if (nearestRouteId) { match = useStore(router.stores.getRouteMatchStore(nearestRouteId), (value) => value); } else { // No route context — will fall through to error handling below match = Vue.ref(undefined); } } const hasPendingRouteMatch = opts.from ? useStore(router.stores.pendingRouteIds, (ids) => ids) : undefined; const isTransitioning = useStore(router.stores.isTransitioning, (value) => value, { equal: Object.is }); const result = Vue.computed(() => { const selectedMatch = match.value; if (selectedMatch === undefined) { const hasPendingMatch = opts.from ? Boolean(hasPendingRouteMatch?.value[opts.from]) : hasPendingNearestMatch.value; if (!hasPendingMatch && !isTransitioning.value && (opts.shouldThrow ?? true)) { if (process.env.NODE_ENV !== 'production') { throw new Error(`Invariant failed: Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`); } invariant(); } return undefined; } return opts.select ? opts.select(selectedMatch) : selectedMatch; }); // Keep eager throw behavior for setups that call useMatch for side effects only. result.value; return result; } //# sourceMappingURL=useMatch.jsx.map