In Remix, prefer sharing functionality by extracting functions. Not creating re-usable API endpoints. 🤔 Let me explain.
Sometimes in Remix apps, I see common functionality extracted to a data route (basically an API endpoint), which multiple routes can use.
For example,
// app/routes/give-treats.ts
export function loader() {
await treats.increment();
return json({
ok: true,
});
}
And then in another route
// app/routes/cats.tsx
export default function Cats() {
const {data, isPending, error} = useQuery('/give-treats');
// ...
}
This can be fine. Especially if you only want to get the data client-side (although try out clientLoaders for this).
But it does have some issues.
Now you have to manage fetching the data yourself. And loading states.
Generic endpoints tend to accumulate complexity. One of the nice things about Remix is a loader can just return the data needed by one route segment.
Instead, if you can, let each loader return all the data needed by a route component.
Have functionality that’s the same between different loaders? Duplicate it…
Just kidding. Extract a function!
// app/routes/cats.tsx
import {giveTreats} from '~/models/petFriends';
export function loader({request}) {
await giveTreats(request);
return json({
ok: true,
});
}
export default function Cats() {
// ...
}
// app/routes/dogs.tsx
import {giveTreats} from '~/models/petFriends';
export function loader({request}) {
await giveTreats(request);
return json({
ok: true,
});
}
export default function Dogs() {
// ...
}
You know, the normal way of sharing code.
Generic routes can be fine. But consider keeping things easier and simpler.