How can I return multiple lines JSX in another return statement in React?
JavascriptReactjsJavascript Problem Overview
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>
)
}}
);
}
Javascript Solutions
Solution 1 - Javascript
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.
Solution 2 - Javascript
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
Solution 3 - Javascript
From React v16.0.0 onwards, it is possible to return multiple elements by wrapping them within an Array
:
render() {
return (
{[1,2,3].map(function (n) {
return [
<h3>Item {n}</h3>.
<p>Description {n}</p>
]
}}
);
}
Also from React v16.2.0, a new feature called React Fragments
is introduced which you can use to wrap multiple elements:
render() {
return (
{[1,2,3].map(function (n, index) {
return (
<React.Fragment key={index}>
<h3>Item {n}</h3>
<p>Description {n}</p>
</React.Fragment>
)
}}
);
}
As per the documentation:
> A common pattern in React is for a component to return multiple
> elements. Fragments let you group a list of children without adding
> extra nodes to the DOM.
>
> Fragments declared with the explicit
-
> {props.items.map(item => (
> // Without the
- {item.term} >
- {item.description} >
key
, React will fire a key warning
> Solution 4 - Javascript
Also, you might want to return several list items in some helper function inside a React component. Just return an array of HTML nodes with the key
attribute:
import React, { Component } from 'react'
class YourComponent extends Component {
// ...
render() {
return (
<ul>
{this.renderListItems()}
</ul>
)
}
renderListItems() {
return [
<li key={1}><a href="#">Link1</a></li>,
<li key={2}><a href="#">Link2</a></li>,
<li key={3} className="active">Active item</li>,
]
}
}
Solution 5 - Javascript
Updated
Use React Fragment. It's simple. Link to fragment documentation.
render() {
return (
<>
{[1,2,3].map((value) => <div>{value}</div>)}
</>
);
}
Old answer - obsolete
With React > 16 you can use react-composite.
import { Composite } from 'react-composite';
// ...
{[1,2,3].map((n) => (
<Composite>
<h2>Title {n}</h2>
<p>Description {n}</p>
</Composite>
))};
Of course, react-composite has to be installed.
npm install react-composite --save
Solution 6 - Javascript
You can use createFragment
here. See Keyed Fragments.
import createFragment from 'react-addons-create-fragment';
...
{[1,2,3].map((n) => createFragment({
h: <h3>...</h3>,
p: <p>...</p>
})
)}
(I am using ES6 and JSX syntax here.)
You first have to add the react-addons-create-fragment
package:
npm install --save react-addons-create-fragment
The advantage over Jan Olaf Krems's solution: React does not complain about the missing key
.
Solution 7 - Javascript
It is simple by React fragment <></>
and React.Fragment
:
return (
<>
{[1, 2, 3].map(
(n, index): ReactElement => (
<React.Fragment key={index}>
<h3>Item {n}</h3>
<p>Description {n}</p>
</React.Fragment>
),
)}
</>
);
Solution 8 - Javascript
This happens when you are not on the current project, I had three projects in one folder and had this error.
Once switched to a project the issue is gone.