Down the rabbithole

ekov @ pm.me

React basics: rendering a list of JSX elements

Recently, I’ve started mentoring a junior developer. Mentoring is a good way to stay sharp on the basics, and to remind one about the confusing parts of React.

Rendering a list of repeating JSX elements is one of these confusing parts for beginners. So let’s get from a naive approach to a more React-like solution.

The naive approach *

Consider a simple component which renders a list of products for a web shop:

const ProductList = () => {
  return (
    <ul>
      <li>Clicky keyboard</li>
      <li>Comfy trackball</li>
      <li>Cushy chair</li>
    </ul>
  )
}

Now, a web shop is not really useful unless you can view individual product pages, or product details at least. Let’s link to stand-alone product pages this time.

const ProductList = () => {
  return (
    <ul>
      <li>
        <a href="/clicky-keyboard">Clicky keyboard</a>
      </li>
      <li>
        <a href="/comfy-trackball">Comfy trackball</a>
      </li>
      <li>
        <a href="/cushy-chair">Cushy chair</a>
      </li>
    </ul>
  )
}

As you can see, rendering a list of things can get repetitive very easily. If we keep up this approach, updating our product list will take a lot more time (imagine having thousands of products!), and we will eventually forget to update one of them.

A better solution *

DRY (don’t repeat yourself), if followed, is one of the most impactful coding principles that will make your code look clean and less bug-prone. Let’s try to achieve the same result as before, but without repeating ourselves.

As JSX is a syntax extension to HTML, we can write practically any JavaScript code in our JSX components. For this particular problem, we will use Array.map.

Let’s put our products in an array first, and then map that array into JSX elements.

The result of this component will be identical to our first list:

const ProductList = () => {
  const products = [
    { name: 'Clicky keyboard', link: '/clicky-keyboard' },
    { name: 'Comfy trackball', link: '/comfy-trackball' },
    { name: 'Cushy chair', link: '/cushy-chair' },
  ]

  return (
    <ul>
      {products.map((product) => (
        <li key={product.link}>
          {product.name}
        </li>
      )}
    </ul>
  )
}

You’ll see that our <li> has a key attribute. Simply put, it helps React know which elements have to be re-rendered. You can read more about it here.

Now, see how little we have to change to update how a product is rendered.

const ProductList = () => {
  const products = [
    { name: 'Clicky keyboard', link: '/clicky-keyboard' },
    { name: 'Comfy trackball', link: '/comfy-trackball' },
    { name: 'Cushy chair', link: '/cushy-chair' },
  ]

  return (
    <ul>
      {products.map((product) => (
        <li key={product.link}>
+         <a href={product.link}>
            {product.name}
+         </a>
        </li>
      )}
    </ul>
  )
}

…and another way *

In the React docs, you’ll see a bit of a different approach, where JSX-rendered lists are first stored in a constant, and then that constant is used later in the return statement. Something like this:

const ProductList = () => {
  const products = [/* same as before */]

  const Products = products.map((product) => (
    <li key={product.link}>
      <a href={product.link}>
        {product.name}
      </a>
    </li>
  )
 
  return (
    <ul>
      {Products}
    </ul>
  )
}

Both solutions are equally viable, you can choose whichever you prefer. That’s it in a nutshell – now you know how to render repeating elements. This is a very common technique that can be used for menu items, all kinds of lists, and any data that can be structured as an array-like.

Thanks for reading, and until next time!

Previous: Framework laptop: first impressions