How To Loop Inside React JSX - React FAQ

Let's assume you're trying to render a dynamic list of items. You already know to use a loop, but you just can't figure out the exact syntax because everything throws an error.

Your first intuition could be to use a for loop like so

export default function App () {
  const list = ["apples", "oranges", "groundnut"];
  return <ul>
      for (var i=0; i < list.length; i++) {
          // Use i + 1 because the first item would have a key of 0
          <li key={i+1}>{list[i]}</li>
      }
  </ul>
}

Oops, we get an error ⚠.

Error from wrong use of for loop

If you take a closer look, you'll see the problem here. There's no return statement in the <li>{...}</li> block and wait, shouldn't we wrap the for loop in another curly brace? Let's try again...

---
<ul>
    {for (var i=0; i < list.length; i++) {
        return <li key={i+1}>{list[i]}</li>
    }}
</ul>
---

I'm sorry I lied, this doesn't work too. There's an explanation for why this doesn't work at the end of the article, but let's just solve the problem already.

The solutions

There're basically 2 easy ways to do this.

Use a map function on the list

export default function App() {
  const list = ["apples", "oranges", "groundnut"];
  return (
    <ul>
      {list.map((listItem, index) => (
        <li key={index}>{listItem}</li>
      ))}
    </ul>
  );
}

Build the jsx tree, then use it in the render function

export default function App() {
  const list = ["apples", "oranges", "groundnut"];
  let items = [];

  for (let i = 0; i < list.length; i++) {
    items.push(<li key={i + 1}>{list[i]}</li>);
  }

  return items;
}

Any of these happens to work

Solution for Looping inside JSX

Why???

The differences between statements and expressions are the key to understanding this problem.

The easiest way to differentiate statements from expressions is their output. An expression produces a value while a statement is executed to make something happen.

Example of statements are if/else, for loops, switch statements, etc. While examples of statements are function calls, map, ternary operation, filter etc. A good place to start to avoid this problem is to prefer expressions over statements in react jsx.

  • Use tenary operators in place of if/else statments
  • Use map in place of for loops
  • Use && instead of switch

I'm not saying these are bad. They're just easier to think of in the context of JSX.

Let's go a little deeper

Congrats if you've got a solution to your problem 🎉🎉🎉. But read on if you're curious about why we're having this problem.

Let's take this block of code from the start of this article

export default function App () {
  const list = ["apples", "oranges", "groundnut"];
  return <ul>
      for (var i=0; i < list.length; i++) {
          <li key={i+1}>{list[i]}</li>
      }
  </ul>
}

The main reason this does not work is because of the nature of react components. React can only take the following types of values as children

  1. strings
  2. single react component
  3. array of react components
// 1. String as React child
<ParentComponent>
  Text String as component children
</ParentComponent>

// 2. Another component as React child
<ParentComponent>
  <ChildComponent />
</ParentComponent>

// 3. Array of components as React Children
<ParentComponent>
    [
        <ChildComponent />,
        <ChildComponent />,
        <ChildComponent />
    ]
</ParentComponent>

When we use the map methods in jsx, it gives us an array of react components (3). But when we use a for loop, it doesn't really return anything. Now you might be thinking, what if we return something from the for loop like this...

<ul>
    {for (var i=0; i < list.length; i++) {
        return <li key={i+1}>{list[i]}</li>
    }}
</ul>

This wouldn't work too. The main reason is that you can't assign the value of a for loop. It's not an expression remember??? The only way a for loop can work is when we push the current loop value into an array and return it at the end like this.

export default function App() {
  const list = ["apples", "oranges", "groundnut"];
  let items = [];

  for (let i = 0; i < list.length; i++) {
    items.push(<li key={i + 1}>{list[i]}</li>);
  }

  return items;
}

In Conclusion

  • Prefer expressions over statements while writing JSX.
  • A litmus test for if something is a statement or expression is if the result can be assigned to a variable.
  • React children can be either a string, another react component, or an array of react components.

I'm glad if this was helpful to you. Please reach out to me on Twitter and tell me what you think...

More Resources