I’m trying to create a footnote component for my new React version of my blog, but, so far, I’m not able to get the numbering right.
I’m applying basically the same logic I did for my Web Components version of the same blog:
- Calculate the current footnote index based on how many footnotes you can
document.querySelectorAll(".footnote")
. - Use that index for the
<sup>
tag where the footnote should appear. - Append the footnote index and content to a footnotes container at the end of the post.
I think this won’t work due to the rendering sequence React uses. Is there a workaround?
Here’s an example of what I have so far:
function Article() {
return (
<article>
<p>The<FootNote html="Footnote 1" /> article content here<FootNote html="Footnote 2" />.</p>
<FootNotesContainer />
</article>
)
}
function FootNotesContainer() {
return (
<div id="footnotes-container">
<h2>Footnotes</h2>
</div>
)
}
function FootNote({ html }) {
const [footNoteLink, setFootNoteLink] = React.useState("")
React.useEffect(() => {
const previousFootnotes =
document.querySelectorAll(".footnote")
const nextFootNoteNumber = previousFootnotes.length
setFootNoteLink(nextFootNoteNumber.toString())
const footNoteContent = document.createElement("div")
footNoteContent.innerHTML = /* html */ `
<a
href="#footnote-base-${nextFootNoteNumber}"
id="footnote-${nextFootNoteNumber}"
className="no-underline"
>${nextFootNoteNumber}</a>:
${html}
`
const footNoteContainer = document.querySelector(
"#footnotes-container"
)
footNoteContainer.appendChild(footNoteContent)
}, [html])
return (
<sup className="footnote">
<a
href={`#footnote-${footNoteLink}`}
id={`footnote-base-${footNoteLink}`}
className="text-orange-400 no-underline"
>
{footNoteLink}
</a>
</sup>
)
}
ReactDOM.createRoot(
document.getElementById("root")
).render(
<Article />
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>