T
TanStack12mo ago
sensitive-blue

Can I make a common loader for few components?

I have a backend server from which I request user details, and it successfully sends the user details. However, the issue is that I only get the user details for specific routes where I use a loader. I want to access the user details on every authenticated route. For example, if I navigate to localhost:5173/, I get the user details because I'm using a loader there. But if I try to access localhost:5173/test or localhost:5173/test2, I don't get the user details, even though all three routes are authenticated. This happens because I haven't used a loader in the test or test2 components. I would like to implement a central loader that can fetch the user details for every authenticated route. Can you help resolve this issue? Would you like help with the implementation details for a central loader solution or do you have any other alternative solution?
No description
No description
No description
No description
4 Replies
national-gold
national-gold12mo ago
put the API call into a beforeLoad, then return the result. now that data is available via context
correct-apricot
correct-apricot12mo ago
What is the advantage of doing that over using route matching out of curiosity? I'm very used to the remix way of doing things and I'm just curious on the tradeoff there?
national-gold
national-gold12mo ago
I don't see how route matching is related here but then again, I have no remix experience
correct-apricot
correct-apricot12mo ago
My understanding is that useMatch finds the data from a specific parent route and allows you to reference it. Here's an example of if I loaded some todos into my dashboard/ route creating a component that references that data from useMatches
// in routes/dashboard.tsx
export const Route = createFileRoute("/dashboard")({
loader: async () => {
const { todos } = await rpc.api.todos.$get({}).then((res) => res.json());

return {
todos,
};
},
component: () => (
<div>
<h1>Dashboard</h1>
<Outlet />
</div>
),
});



// in /components/TodosList, but has
// to be rendered in a route that is either `/dashboard` or a child route of `/dashboard`
export const TodosList = () => {
/*
For the record between the typesafety and the select on useMatch, the DX of this feature is WAY better than it is in remix and this allows for so much more flexibility and clean coding habits.
*/
const todos = useMatch({
from: "/dashboard",
select: (d) => d.loaderData?.todos,
})

return (
<section
style={{
display: "flex",
flexDirection: "column",
gap: 10,
}}
>
{todos?.map((todo) => <div key={todo.id}>{todo.title}</div>)}
</section>
);
};
// in routes/dashboard.tsx
export const Route = createFileRoute("/dashboard")({
loader: async () => {
const { todos } = await rpc.api.todos.$get({}).then((res) => res.json());

return {
todos,
};
},
component: () => (
<div>
<h1>Dashboard</h1>
<Outlet />
</div>
),
});



// in /components/TodosList, but has
// to be rendered in a route that is either `/dashboard` or a child route of `/dashboard`
export const TodosList = () => {
/*
For the record between the typesafety and the select on useMatch, the DX of this feature is WAY better than it is in remix and this allows for so much more flexibility and clean coding habits.
*/
const todos = useMatch({
from: "/dashboard",
select: (d) => d.loaderData?.todos,
})

return (
<section
style={{
display: "flex",
flexDirection: "column",
gap: 10,
}}
>
{todos?.map((todo) => <div key={todo.id}>{todo.title}</div>)}
</section>
);
};
In the docs, what I saw using the context for was dependency injection and creating custom methods that you can call. For example creating a fetchTodos method and accessing it in a child component. But this is more about fetching the data in the loader, then referencing that data in child components rather than the method to grab that data (This is exactly how you would do it in remix, although the DX in Tanstack Router is SOOO much better)

Did you find this page helpful?