121

A single line works fine:

render: function () {
  return (
    {[1,2,3].map(function (n) {
      return <p>{n}</p>
    }}
  );
}

But not for multiple lines:

render: function () {
  return (
    {[1,2,3].map(function (n) {
      return (
        <h3>Item {n}</h3>
        <p>Description {n}</p>
      )
    }}
  );
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shawn
  • 32,509
  • 17
  • 45
  • 74

8 Answers8

162

Try to think of the tags as function calls (see the documentation). Then the first one becomes:

{[1,2,3].map(function (n) {
  return React.DOM.p(...);
})}

And the second one:

{[1,2,3].map(function (n) {
  return (
    React.DOM.h3(...)
    React.DOM.p(...)
  )
})}

It should now be clear that the second snippet doesn't really make sense (you can't return more than one value in JavaScript). You have to either wrap it in another element (most likely what you'd want, that way you can also provide a valid key property), or you can use something like this:

{[1,2,3].map(function (n) {
  return ([
    React.DOM.h3(...),
    React.DOM.p(...)
  ]);
})}

With JSX syntactic sugar:

{[1,2,3].map(function (n) {
  return ([
    <h3></h3>, // note the comma
    <p></p>
  ]);
})}

You don't need to flatten the resulting array. React will do that for you. See the following fiddle http://jsfiddle.net/mEB2V/1/. Again: Wrapping the two elements into a div/section will most likely be better long term.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jan Olaf Krems
  • 2,274
  • 1
  • 14
  • 11
  • 4
    Yep actually clearly documented http://facebook.github.io/react/tips/maximum-number-of-jsx-root-nodes.html – Shawn May 24 '14 at 03:42
  • 2
    Using return ([...]) without the flatten bit gives me the markup exactly as I wanted, though the returned array mustn't have been flattend but in my particular case it doesn't affect the final output. Or is it? – Shawn May 24 '14 at 03:52
  • Thanks! TIL! Updating my answer to include a link to a JSFiddle that shows that flatten is optional. Will also include the link to the React docs. – Jan Olaf Krems May 24 '14 at 04:37
  • The second example is missing a closing bracket for the map function: the last line has to be '})}' instead of '}}'. Same goes for the first example. – fret Feb 23 '15 at 09:59
  • 13
    This no longer works (as of 0.9ish) `Uncaught Error: Invariant Violation: Product.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.` – dogmatic69 Aug 21 '15 at 14:25
  • Returning an array in a ternary seems to be working for me with 0.13.3 — https://gist.github.com/TimFletcher/41299e54373a37873a91 – Tim Fletcher Oct 29 '15 at 13:16
  • 2
    @TimFletcher It's fine to return an array as *part of* rendering a component, e.g `
    { this.props.foos.map(function() { return }) }
    `. But the `render` function of the component can't return that array without wrapping it, e.g. in a div.
    – Henrik N Jul 02 '16 at 22:17
  • returning an array works but react complains about the missing keys when flattening the array. – sylvain Aug 23 '16 at 13:16
  • @JanOlafKrems funny to stumble over you here on stackoverflow! your answer helped me a lot, thanks :) – nerdess Aug 03 '17 at 09:27
  • More [exact link](https://reactjs.org/docs/jsx-in-depth.html#jsx-children) regarding returning arrays (third example). – x-yuri Mar 30 '18 at 15:13
  • JSX Sugar adds sweetness in my day. Thanks @JanOlafKrems – Utkarsh Jul 12 '20 at 10:58
37

It seems Jan Olaf Krems's answer about returning an array no longer applies (maybe since React ~0.9, as @dogmatic69 wrote in a comment).

The documentation says you need to return a single node:

Maximum Number of JSX Root Nodes

Currently, in a component's render, you can only return one node; if you have, say, a list of divs to return, you must wrap your components within a div, span or any other component.

Don't forget that JSX compiles into regular JS; returning two functions doesn't really make syntactic sense. Likewise, don't put more than one child in a ternary.

In many cases you can simply wrap things in a <div> or a <span>.

In my case, I wanted to return multiple <tr>s. I wrapped them in a <tbody> – a table is allowed to have multiple bodies.

As of React 16.0, returning an array is apparently allowed again, as long as each element has a key: New render return types: fragments and strings

React 16.2 lets you surround a list of elements with <Fragment>…</Fragment> or even <>…</>, if you prefer that to an array: https://reactjs.org/docs/fragments.html

Henrik N
  • 15,786
  • 5
  • 82
  • 131
  • @Banjocat I'm afraid I don't know :/ You are allowed to *nest* lists, so you could return something like `
    • one
    • two
  • ` if that works in your situation. Or: A wrapping div wouldn't strictly be valid but maybe it renders fine in all relevant browsers? If you try it, let us know. – Henrik N Nov 10 '15 at 18:22
  • 1
    @Banjocat...I'd love to know a better answer to your question. Maybe you should pose it as a regular stackoverflow question and see if you get a different answer. – user1175849 Nov 24 '15 at 11:22
  • @user1175849 Maybe *you* could post that question then :) – Henrik N Nov 25 '15 at 12:11
  • Create a list on the object and return each `
  • ` into it. Then when you want to add more, you do `this.listItems.push(
  • )`. If I remember correctly, you can do `
      {this.listItems}
    `. – Kevin Ghadyani Jul 22 '16 at 08:52