ReactT2_1200x303

Wondering how to create loops in React? Learn about JSX and how to use methods like the map function to loop inside React JSX and render a list of items.

JSX in a Nutshell

If you have worked with React before, then there is a high probability that you know what JSX is, or have at least heard of it. JSX is a custom syntax extension to JavaScript which is used for creating markup with React. It might remind you a bit of a templating language, but with JSX you can use the full power of JavaScript. However, remember that JSX will not work directly in browsers and requires a build step to convert JSX markup into React.createElement function calls.

// JSX example

return (
  <div>
    <button onClick={onClickHandler}>Submit</button>
  </div>
)

// The above will be converted to something like this

return React.createElement(
    "div",
    {},
    React.createElement(
      "button",
      {
        onClick: e => {}
      },
      "Submit"
    )
  );

You can read more about it on the React website.

How to Loop in JSX Using map Function

When I first started with React, I realized quite early that I did not know how to loop through an array and render a list of items. The most common way of doing that is with the map function that will return JSX. You will rarely need a loop other than this one. Below you can see how it works.

import React from ‘react’

const RenderList = props => {
  const animals = ["Dog", "Bird", "Cat", "Mouse", "Horse"];

  return (
    <ul>
      {animals.map(animal => (
        <li>{animal}</li>
      ))}
    </ul>
  );
};

You should see a rendered list. However, if you check the console log, you will see that there is a warning like, “Warning: Each child in a list should have a unique key prop.” Whenever you use a loop it is important to provide a unique key attribute. The reason is that React uses these keys to track if items were changed, added, or removed. Well, we could just use a loop index, couldn’t we?

  return (
    <ul>
      {animals.map((animal, index) => (
        <li key={index}>{animal}</li>
      ))}
    </ul>
  );

Thanks to adding keys there are no more warnings in the console. However, there is more you need to know. Using an index as a key in certain situations could lead us into a pitfall and cause bugs.

Why is key Important in Loops?

As I mentioned earlier, React uses the key attribute to track if there were any changes made. Imagine a scenario in which you have a list of items that can be reordered. If indexes are used as keys and we change the order of items, will React know about it? Well, it might not, as even though the order of items in an array changed, the keys did not. Therefore, the list would not be re-rendered.

So, as the rule of thumb, if you have an array that can change, then use a unique id. If it is not available, then create one for each item before the list is rendered. Otherwise, it is ok to use an index for the key attribute.

// Example with an id

const RenderList = props => {
  const animals = [
    { id: 1, animal: "Dog" },
    { id: 2, animal: "Bird" },
    { id: 3, animal: "Cat" },
    { id: 4, animal: "Mouse" },
    { id: 5, animal: "Horse" }
  ];

  return (
    <ul>
      {animals.map(item => (
        <li key={item.id}>{item.animal}</li>
      ))}
    </ul>
  );
};

So far, we have used the map function directly in the return expression. However, if you would like, you can first use a variable to store results of the map and then render content of the variable.

  const renderAnimals = animals.map(item => (
    <li key={item.id}>{item.animal}</li>
  ));

  return <ul>{renderAnimals}</ul>;

If you prefer, you can even use a function.

  const getAnimalsContent = animals => animals.map(item => (
    <li key={item.id}>{item.animal}</li>
  ));

  return <ul>{getAnimalsContent(animals)}</ul>;

Using Other Loops in React

99.99% of the time, I use the map function to render a list of items and, to be honest, I can’t recall any scenario in which I needed another loop. Nevertheless, you are not bound to it and can use any loop to render a list. All of these work fine:

For-of

  const getAnimalsContent = animals => {
    let content = [];
    for (let item of animals) {
      content.push(<li key={item.id}>{item.animal}</li>);
    }
    return content;
  };

  return <ul>{getAnimalsContent(animals)}</ul>;

For-in

  const getAnimalsContent = animals => {
    let content = [];
    for (let idx in animals) {
      const item = animals[idx];
      content.push(<li key={item.id}>{item.animal}</li>);
    }
    return content;
  };

  return <ul>{getAnimalsContent(animals)}</ul>;

For-standard

  const getAnimalsContent = animals => {
    let content = [];
    for (let i = 0; i < animals.length; i++) {
      const item = animals[i];
      content.push(<li key={item.id}>{item.animal}</li>);
    }
    return content;
  };

  return <ul>{getAnimalsContent(animals)}</ul>;

Filter

The filter function can be used together with map to filter out items before they are rendered. For instance, in the example below only ‘Mouse’ and ‘Horse’ items will be rendered.

// Filter out any animals that do not contain ‘e’ character.
  const getAnimalsContent = animals =>
    animals
      .filter(item => item.animal.includes("e"))
      .map(item => <li key={item.id}>{item.animal}</li>);

  return <ul>{getAnimalsContent(animals)}</ul>;

Reduce

The filter example above can be enhanced with the reduce method so instead of having two loops – one for filtering and one for creating JSX content, we will just have one.

  const getAnimalsContent = animals =>
    animals.reduce((acc, item) => {
      if (item.animal.includes("e")) {
        acc.push(<li key={item.id}>{item.animal}</li>);
      }
      return acc;
    }, []);

  return <ul>{getAnimalsContent(animals)}</ul>;

If for any reason you want to experiment, then you can even use recursion to render a list. However, I would not recommend doing that and, in most cases, you should really stick with the map function.

  const getAnimalsContent = (animals, content = []) => {
    if (!animals.length) return content;
    const [item, ...restAnimals] = animals;
    content.push(<li key={item.id}>{item.animal}</li>);
    return getAnimalsContent(restAnimals, content);
  };

  return <ul>{getAnimalsContent(animals)}</ul>;

As you can see there are quite a few different ways in which you can render a list of items in React. I hope that after reading this article you are now more confident with React and know how to use loops in JSX.


Thomas Findlay
About the Author

Thomas Findlay

Thomas Findlay is a web and mobile developer, mentor, technical writer and consultant with almost six years of experience. He specializes in frontend web technologies including Vue.js, React.js, React Native for mobile applications, along with backend: PHP, Laravel, Python, Flask, Node.js and Express.js. Thomas has designed and developed websites and mobile applications for individuals and small and large businesses. Learn more about Thomas at https://www.codementor.io/thomas478

Related Posts

Comments

Comments are disabled in preview mode.