As we know, we can create a link
function in a component, but it only contains static links, not dynamic ones. To create a dynamic <link>
tag, we need to understand a hook in Remix and how the meta
function receives data in its function parameter.
import { json } from '@remix-run/node'
export const meta = ({ data }) => {
const { article } = data
return [
{ title: `${article.title}` },
{
name: 'description',
content: `Explore the insights and perspectives shared by ${article.username}. Stay informed and updated.`,
},
]
}
// Loader function to fetch post data
export async function loader({ params }) {
const { postid } = params
console.log(postid)
if (!postid) {
throw new Response('Id not found', { status: 404 })
}
if (postid == 'favicon.ico') return
const article = await service.getPost(postid)
if (!article) {
throw new Response('article not found', { status: 404 })
}
return json({ article })
}
As i research on this topic i find that it internally uses a hook but may be i was wrong anyway the perpose is fullfilled.
So there is a hook useMatches()
that takes data from loader from active routes and there now data is passed from meta function to root.jsx
file.
import {Meta} from '@remix-run/react'
export function Layout({ children }) {
return (
<html lang="en" className="dark bg-black">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
</head>
<body className="bg-black">
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
)
}
Create dynamic links is mainly used to use loader data in link function so we create a component DynamicLinks
.
import * as React from 'react'
import { useMatches } from '@remix-run/react'
export const DynamicLinks = () => {
const matches = useMatches() //takes loader data from active routes
let links = []
// loop the data
for (const match of matches) {
if (typeof match.handle?.dynamicLinks === 'function') {
const routeLinks = match.handle.dynamicLinks({
data: match.data || {},
})
if (Array.isArray(routeLinks)) {
links.push(...routeLinks)
} else {
console.error(
`dynamicLinks for route ${match.id} must return an array.`
)
}
}
}
return (
<>
{links.map((link, index) => (
<link key={index} {...link} />
))}
</>
)
}
There we use in route components like.
import { json } from '@remix-run/node'
// Loader function to fetch post data
export async function loader({ params }) {
const { postid } = params
if (!postid) {
throw new Response('Id not found', { status: 404 })
}
if (postid == 'favicon.ico') return
const article = await service.getPost(postid)
if (!article) {
throw new Response('article not found', { status: 404 })
}
return json({ article })
}
// for dynamic links
export const handle = {
dynamicLinks: ({ data }) => {
const { article } = data
if (!article) return []
return [
{ rel: 'canonical', href: `https://www.wesite.com/post/${article.$id}` },
]
},
}
Then use in root.jsx
file link links
tag.
import { DynamicLinks } from './components/DynamicLinks.jsx'
import { Links, Meta } from '@remix-run/react'
// Layout component for consistent structure
export function Layout({ children }) {
return (
<html lang="en" className="dark bg-black">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
<DynamicLinks />
/>
</head>
<body className="bg-black">
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
)
}