remix
remix copied to clipboard
docs: explain why links can't access data
What version of Remix are you using?
1.7.0
Steps to Reproduce
Currently the MetaFunction is described like this:
export interface MetaFunction<Loader extends LoaderFunction | unknown = unknown, ParentsLoaders extends Record<string, LoaderFunction> = {}> {
(args: {
data: Loader extends LoaderFunction ? SerializeFrom<Loader> : AppData;
parentsData: {
[k in keyof ParentsLoaders]: SerializeFrom<ParentsLoaders[k]>;
} & RouteData;
params: Params;
location: Location;
}): HtmlMetaDescriptor;
}
While the LinksFunction is described like this:
export interface LinksFunction {
(): LinkDescriptor[];
}
Expected Behavior
I'd like to access data when exporting my links function in order to grab some info, eg:
export const links: LinksFunction<typeof loader> = ({ data }) => {
const linkArr: LinkDescriptor[] = []
if (data.pagination.page > 1) {
linkArr.push({ rel: 'prev', href: `/page/${data.pagination.page - 1}` })
}
if (data.pagination.page < data.pagination.pages) {
linkArr.push({ rel: 'next', href: `/page/${data.pagination.page + 1}` })
}
return linkArr
}
Actual Behavior
I can't access data, thus I can't set up links that depend on them:
export const links: LinksFunction<typeof loader> = ({ data }) => {
const linkArr: LinkDescriptor[] = []
if (data.pagination.page > 1) {
linkArr.push({ rel: 'prev', href: `/page/${data.pagination.page - 1}` })
}
if (data.pagination.page < data.pagination.pages) {
linkArr.push({ rel: 'next', href: `/page/${data.pagination.page + 1}` })
}
return linkArr
}
For reference: https://developers.google.com/search/blog/2011/09/pagination-with-relnext-and-relprev
links cannot access data, because if it did, it would introduce a waterfall where styles can't be loaded until after data resolves. Remix needs links to be "static" in order to do its thing, and therefore, it cannot depend on data.
For your use-case, you can use https://github.com/sergiodxa/remix-utils#dynamiclinks which internally uses handle().
This should definitely be explained in the documentation, so labeling this issue as a documentation issue.
@machour see you changed the issue title from "Access to data/location on LinksFunction" and while I agree with the data portion of your response, what about location? Could remix pass the location to the links function?
@tom-sherman looks like you can do this using the meta function if you update to the V2 conventions and use matches and/or location which are supplied
https://remix.run/docs/en/main/pages/v2#updating-to-the-new-meta
@tom-sherman I know this is almost four months later, but like @rub1e says, you can get the current route info from matches:
export function meta({ matches }: V2_MetaArgs) {
const leaf = matches.at(-1);
const { page } = leaf!.params;
const pageNum = Number(page);
const prev = pageNum > 1 ? pageNum - 1 : null;
const next = pageNum < 10 ? pageNum + 1 : null;
// Remix will ignore non-truthy entries
return [
prev ? { tagName: "link", rel: "prev", href: `/page/${prev}` } : null,
next ? { tagName: "link", rel: "next", href: `/page/${next}` } : null,
];
}