T
TanStack•2y ago
conventional-tan

Does tanstack router not promote potentially harmful conventions?

The useSearch and useParams hooks that exist on the Route instances could be promoting a harmful convention. Since all Route instances must have a runtime reference to their parents, using the hooks via the Route instances means that any hook consumer will have to effectively depend on the entire route tree. Here's an example of what I find problematic:
// MyRouteComponent.ts
import { useNavigate } from "@tanstack/react-router";
import { myRoute } from "./routes"; // Contains potentially hundreds of routes, which we now indirectly depend on

export function MyRouteComponent() {
const navigate = useNavigate();
const search = myRoute.useSearch();

return (
<>
Input date: {search.date?.toString()}
<button
onClick={() =>
navigate({
to: myRoute.fullPath,
search: { date: new Date() },
})
}
>
Update date
</button>
</>
);
}
// MyRouteComponent.ts
import { useNavigate } from "@tanstack/react-router";
import { myRoute } from "./routes"; // Contains potentially hundreds of routes, which we now indirectly depend on

export function MyRouteComponent() {
const navigate = useNavigate();
const search = myRoute.useSearch();

return (
<>
Input date: {search.date?.toString()}
<button
onClick={() =>
navigate({
to: myRoute.fullPath,
search: { date: new Date() },
})
}
>
Update date
</button>
</>
);
}
The code above will practically hard couple all components that use hooks this way to the entire application, if done consistently. If anyone imports MyRouteComponent.ts, they will also indirectly be importing the entire route tree since the component depends on routes.ts. This can easily make it problematic to run components in isolation, i.e. in storybook or unit tests. To avoid this problem, I just built my first app using tanstack router and decided to abstract away the useSearch and useNavigate calls and instead loose couple routes and route components via props. You can see my approach here: https://github.com/kasper573/yas/tree/master/libraries/yas-router#enhanced-route-components Would love to hear what you guys think of this problem and my solution!
GitHub
yas/libraries/yas-router at master · kasper573/yas
Yet Another Stack. Contribute to kasper573/yas development by creating an account on GitHub.
13 Replies
foreign-sapphire
foreign-sapphire•2y ago
RouteApi class | TanStack Router Docs
The RouteApi class provides type-safe version of common hooks like useParams, useLoaderData, useRouteContext, and useSearch that are pre-bound to a specific route ID and corresponding registered route types. RouteApi constructor
conventional-tan
conventional-tanOP•2y ago
Are you sure that's what I'm referring to? Maybe I'm missing something, but it doesn't look like that can be used from a component without having access to the route instance.
foreign-sapphire
foreign-sapphire•2y ago
GitHub
router/examples/react/basic-file-based-codesplitting/src/routes/pos...
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
conventional-tan
conventional-tanOP•2y ago
Oh I see! Thanks for clarifying. Yes, that does indeed solve the problem 🙂 Great work!
foreign-sapphire
foreign-sapphire•2y ago
btw, you can also use the "global" hooks like this useSearch({from: '/route-id'})
conventional-tan
conventional-tanOP•2y ago
Do you happen to know how it behaves in isolation? If I render the component using the RouteApi instance inside of a router that doesn't have access that that particular route?
foreign-sapphire
foreign-sapphire•2y ago
how would the router not have access to that route?
conventional-tan
conventional-tanOP•2y ago
in a unit test
foreign-sapphire
foreign-sapphire•2y ago
it must have when building the routeTree
conventional-tan
conventional-tanOP•2y ago
a common use case is to render a page in a unit test, knowing that their links may not be functional since we're outside the router, but we still want to test the rest of the page functionality. if the page component crashes due to the router hook not being able to do it's thing, that's the type of issue I'm talking about
foreign-sapphire
foreign-sapphire•2y ago
sorry don't know how it would behave in this setup, you need to test this
conventional-tan
conventional-tanOP•2y ago
all right! I'll test with the RouteApi, and if I find any problems I'll make a sandbox with a repro! Thanks for the speedy response 🙂
automatic-azure
automatic-azure•2y ago
currently I handle hard errors within Storybook context like this:
const selectedFilters = useSearch({
...(isStorybook
? { strict: false }
: {
from: isCollection ? "/_dashboard/collections" : "/_dashboard/exercises"
})
})
const selectedFilters = useSearch({
...(isStorybook
? { strict: false }
: {
from: isCollection ? "/_dashboard/collections" : "/_dashboard/exercises"
})
})
Is there a more elegant solution lets say to set {strict:false} in case of Storybook context for all useSearch hooks?

Did you find this page helpful?