@tanstack/vue-router
Version:
Modern and scalable routing for Vue applications
78 lines • 3.58 kB
JSX
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