A good[ish] website
Web development blog, loads of UI and JavaScript topics
When rendering deep lists, recursion is pretty much the only right way to do it. Recursive React components work like a charm.
Take the following shape, a deep array that renders a table of contents, this specifically is taken from the style guide post:
const toc = {
items: [
{
url: '#this-is-an-h2-heading',
title: 'This is an h2 heading',
items: [
{
url: '#heres-an-h3',
title: 'Here’s an h3',
items: [
{
url: '#h4-deep-enough',
title: 'H4, deep enough?',
items: [
{
url: '#and-an-h5',
title: 'And an h5 😬'
}
]
}
]
}
]
},
{
url: '#lists',
title: 'Lists',
items: [
{
url: '#unordered-list',
title: 'Unordered list'
},
{
url: '#ordered-list',
title: 'Ordered list'
}
]
},
{
url: '#code',
title: 'Code',
items: [
{
url: '#inline-code',
title: 'Inline code'
},
{
url: '#sample-output-samp',
title: 'Sample output, samp'
}
]
},
{
url: '#embeds',
title: 'Embeds'
},
{
url: '#media',
title: 'Media'
},
{
url: '#html-elements',
title: 'HTML elements',
items: [
{
url: '#address',
title: 'Address'
},
{
url: '#superscript-and-subscript',
title: 'Superscript and subscript'
}
]
},
{
url: '#boxes',
title: 'Boxes'
}
]
}
See how some of the elements contain items
and again items
... a copy of itself in a way, a fractal-like structure. Whenever there’s fractals, there’s recursion.
The markup for the list should look something like this:
<ul>
<li>
<a href="#this-is-an-h2-heading">This is an h2 heading</a>
<ul>
<li>
<a href="#heres-an-h3">Here’s an h3</a>
<ul>
<li>
<a href="#h4-deep-enough">'H4, deep enough?'</a>
<ul>
<li>
<a href="#and-an-h5">And an h5 😬</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>
<a href="#lists">Lists</a>
</li>
<!-- More item here... -->
</ul>
If you try to render the list without recursion, very soon you’ll be faced with the pyramid of doom:
const TableOfContents = ({ toc }) => (
<ul>
{(toc.items || []).map(item => (
<li key={toc.url}>
<a href={toc.url}>{toc?.title}</a>
{(item.items || []).map(item => (
<ul>
<li>
<a href={toc.url}>{toc?.title}</a>
{/* ❌ The pyramid of doom ❌ */} </li>
</ul>
)}
</li>
))}
</ul>
)
You could keep adding maps there until you’re deep enough and you’d probably be fine with it, but is that good code?
It’s much nicer to have a function that calls itself as many times as is needed, React components can be recursive like any other functions:
const TocItem = ({ toc }) => {
const subItem = (toc.items || []).map(item => (
<ul key={item.url}>
{/* ✅ Recursion ✅ */}
<TocItem toc={item} type="child" /> </ul>
))
return (
<li key={toc.title}>
<a href={toc.url}>{toc.title}</a>
{subItem}
</li>
)
}
const TableOfContents = ({ toc }) => (
<ul>
{(toc.items || []).map((item, index) => (
<TocItem key={index} toc={item} /> ))}
</ul>
)
Some programmers don’t like recursion, and that’s fair, you don’t need to stuff it everywhere. Sometimes it just happens to be the right tool for the job.
Hope this was helpful, thanks for reading!
Comments would go here, but the commenting system isn’t ready yet, sorry.