Next.js Discord

Discord Forum

Common modular "template" for page(s)

Answered
Painted Redstart posted this in #help-forum
Open in Discord
Painted RedstartOP
I'm making wiki-like pages using mdx and would like to add a common(ly formated?) sidebar & header that contains information about the article (such as subheader anchors, date published, author etc.). Currently the header is child of the body of the article.
The only method I can think of for accomplishing this is to have a parent class that generates the sidebar & header, and then extend that for each page, but I don't think I can do this with the mdx format.

template seems promising in this regard, but it also seems that the rendering process makes template a parent to a page, which means I cant send data back up from a page to a template so the template can use it.
https://nextjs.org/docs/app/api-reference/file-conventions/template

Note: I keep this data in the metadata export because it allows me to also set the metadata for the site to this data.

Here's what I currently have:
import ArticleHeader from 'components/ArticleHeader'

export const metadata = {
    title: 'A Title',
    description: 'Small Description',
    authors: [{name: 'I.M. Writer'}],
    date: "12-25-97",
}

<ArticleHeader metadata = {metadata}/>

Some cool information goes here...


How would I go about creating a "default template" that allows me to pass data for it to populate itself, and then embed a document in that templet?
Answered by Painted Redstart
oh, and here's a diagram i made while studying your code, i know you said it's a bit difficult to explain so actually mapping out the data flow was very useful. Couldn'tve pieced it together without your example!
View full answer

15 Replies

@Painted Redstart I'm making wiki-like pages using `mdx` and would like to add a common(ly formated?) sidebar & header that contains information about the article (such as subheader anchors, date published, author etc.). Currently the header is child of the body of the article. The only method I can think of for accomplishing this is to have a parent class that generates the sidebar & header, and then extend that for each page, but I don't think I can do this with the `mdx` format. `template` seems promising in this regard, but it also seems that the rendering process makes `template` a parent to a `page`, which means I cant send data back up from a `page` to a `template` so the `template` can use it. https://nextjs.org/docs/app/api-reference/file-conventions/template Note: I keep this data in the metadata export because it allows me to also set the metadata for the site to this data. Here's what I currently have: mdx import ArticleHeader from 'components/ArticleHeader' export const metadata = { title: 'A Title', description: 'Small Description', authors: [{name: 'I.M. Writer'}], date: "12-25-97", } <ArticleHeader metadata = {metadata}/> Some cool information goes here... How would I go about creating a "default template" that allows me to pass data for it to populate itself, and then embed a document in that templet?
no idt template.js is the way here.

if the data can be fetched in bulk, the simplest way is to use usePathname/useParams and get the page data on the client side
"use client";
export function PostMetadata({ allPostData }) {
  const { slug } = useParams();
  const post = allPostData.find(post => post.slug === slug);
  if (!post) notFound();
  return <div>{post.title}</div>;
}


if you have many pages or for any reasons you'd like to filter on the server, then use parallel routes https://nextjs.org/docs/app/building-your-application/routing/parallel-routes
Painted RedstartOP
im kinda new with react/nextjs but this seems like an antipattern to me? surely there's a way to do this at build time if all the data is static
parallel routes are static. same as the client-side filtering method: the data is also static.
Painted RedstartOP
ah ok, i was under the impression that client side rendering happens during runtime
Painted RedstartOP
ah i think im starting to piece this together, im a bit tired tonight and will implement tomorrow, as well as do a little writeup, the examples helped a lot though, thank you
Painted RedstartOP
im having trouble with the client and server renders conflicting, currently, it's structured similar to your blog, joulev, where there is a centralized ledger of metadata in meta-list, which gets passed to each individual article so they can pick out and export their metadata; and which are used by article-content.jsx, which exports <ThisArtcleHeader> (this component is what renders above "subheader 1" and is in layout.jsx:
export default function RootLayout({children}) {
    return (
        <main>
            <ThisArticleHeader/>
            {children}
        </main>
    )
}


article-content.jsx:
"use client";

import { usePathname } from "next/navigation";
import getArticleMetadata from "src/getarticlemeta.mjs";
import ArticleHeader from "components/ArticleHeader";

function getThisMeta() {
    const slug = usePathname().split("/").pop()
    return getArticleMetadata(slug) // find article metadata by matching against slug in `meta-list`
}

export function ThisArticleHeader() {
    const metadata = getThisMeta()
    return <ArticleHeader metadata = {metadata}/>
}


the relevant bits of ArticleHeader are:
//...
let version_number = props.metadata.version_number
let style_symbol

//version numbers obey lexiographic ordering
if(version_number > process.env.KRISTAL_VERSION) {
    style_symbol = styles.beta
    version_number = version_number + " (BETA)"
}else if(version_number < process.env.KRISTAL_VERSION) {
    style_symbol = styles.old
    version_number = version_number + " (OLD)"
} else {
    style_symbol = styles.stable
}
// ...
 let content = <>
        <div>
            <span className={style_symbol}>{version_number}</span>
//...</>

return <div {...props}>{content}</div>;

The image on the left is the desired outcome (it appears for a moment) while the one on the right is my current issue, and nextjs gives:
Warning: Text content did not match. Server: "0.1.0 (OLD)" Client: "0.1.0"
Painted RedstartOP
disabling ssr does not help, which makes sense since i think i want the server's render, not the client's. im still confused why they differ at all, a bit more testing makes it seem like the conditional is cached and else always executes even when the preceeding conditions are met?
@Painted Redstart im having trouble with the client and server renders conflicting, currently, it's structured similar to your blog, joulev, where there is a centralized ledger of metadata in `meta-list`, which gets passed to each individual article so they can pick out and export their metadata; and which are used by `article-content.jsx`, which exports `<ThisArtcleHeader>` (this component is what renders above "subheader 1" and is in `layout.jsx`: jsx export default function RootLayout({children}) { return ( <main> <ThisArticleHeader/> {children} </main> ) } `article-content.jsx`: jsx "use client"; import { usePathname } from "next/navigation"; import getArticleMetadata from "src/getarticlemeta.mjs"; import ArticleHeader from "components/ArticleHeader"; function getThisMeta() { const slug = usePathname().split("/").pop() return getArticleMetadata(slug) // find article metadata by matching against slug in `meta-list` } export function ThisArticleHeader() { const metadata = getThisMeta() return <ArticleHeader metadata = {metadata}/> } the relevant bits of `ArticleHeader` are: jsx //... let version_number = props.metadata.version_number let style_symbol //version numbers obey lexiographic ordering if(version_number > process.env.KRISTAL_VERSION) { style_symbol = styles.beta version_number = version_number + " (BETA)" }else if(version_number < process.env.KRISTAL_VERSION) { style_symbol = styles.old version_number = version_number + " (OLD)" } else { style_symbol = styles.stable } // ... let content = <> <div> <span className={style_symbol}>{version_number}</span> //...</> return <div {...props}>{content}</div>; The image on the left is the desired outcome (it appears for a moment) while the one on the right is my current issue, and nextjs gives: `Warning: Text content did not match. Server: "0.1.0 (OLD)" Client: "0.1.0"`
Looks like you need to name the env var NEXT_PUBLIC_KRISTAL_VERSION
Yeah
Painted RedstartOP
yea that fixed the problem completely :P i wouldve never figured that out without your help, thank you!
You’re welcome
Answer