How can I render repeating React elements?

To expand on Ross Allen's answer, here is a slightly cleaner variant using ES6 arrow syntax.

{this.props.titles.map(title =>
  <th key={title}>{title}</th>
)}

It has the advantage that the JSX part is isolated (no return or ;), making it easier to put a loop around it.


You can put expressions inside braces. Notice in the compiled JavaScript why a for loop would never be possible inside JSX syntax; JSX amounts to function calls and sugared function arguments. Only expressions are allowed.

(Also: Remember to add key attributes to components rendered inside loops.)

JSX + ES2015:

render() {
  return (
    <table className="MyClassName">
      <thead>
        <tr>
          {this.props.titles.map(title =>
            <th key={title}>{title}</th>
          )}
        </tr>
      </thead>
      <tbody>
        {this.props.rows.map((row, i) =>
          <tr key={i}>
            {row.map((col, j) =>
              <td key={j}>{col}</td>
            )}
          </tr>
        )}
      </tbody>
    </table>
  );
} 

JavaScript:

render: function() {
  return (
    React.DOM.table({className: "MyClassName"}, 
      React.DOM.thead(null, 
        React.DOM.tr(null, 
          this.props.titles.map(function(title) {
            return React.DOM.th({key: title}, title);
          })
        )
      ), 
      React.DOM.tbody(null, 
        this.props.rows.map(function(row, i) {
          return (
            React.DOM.tr({key: i}, 
              row.map(function(col, j) {
                return React.DOM.td({key: j}, col);
              })
            )
          );
        })
      )
    )
  );
} 

Since Array(3) will create an un-iterable array, it must be populated to allow the usage of the map Array method. A way to "convert" is to destruct it inside Array-brackets, which "forces" the Array to be filled with undefined values, same as Array(N).fill(undefined)

<table>
    { [...Array(3)].map((_, index) => <tr key={index}/>) }
</table>

Another way would be via Array fill():

<table>
    { Array(3).fill(<tr/>) }
</table>

⚠️ Problem with above example is the lack of key prop, which is a must.
(Using an iterator's index as key is not recommended)


Nested Nodes:

const tableSize = [3,4]
const Table = (
    <table>
        <tbody>
        { [...Array(tableSize[0])].map((tr, trIdx) => 
            <tr key={trIdx}> 
              { [...Array(tableSize[1])].map((a, tdIdx, arr) => 
                  <td key={trIdx + tdIdx}>
                  {arr.length * trIdx + tdIdx + 1}
                  </td>
               )}
            </tr>
        )}
        </tbody>
    </table>
);

ReactDOM.render(Table, document.querySelector('main'))
td{ border:1px solid silver; padding:1em; }
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<main></main>