How to render react components by using map and join?
Update with React 16: It's now possible to render strings directly, so you can simplify your code by removing all the useless <span>
tags.
const list = ({ data }) => data.reduce((prev, curr) => [ prev, ', ', curr ]);
A simple solution is to use reduce()
without second argument and without spreading the previous result:
class List extends React.Component {
render() {
<div>
{this.props.data
.map(t => <span>{t}</span>)
.reduce((prev, curr) => [prev, ', ', curr])}
</div>
}
}
Without second argument, reduce()
will start at index 1 instead of 0, and React is perfectly happy with nested arrays.
As said in the comments, you want to only use this for arrays with at least one item, because reduce()
without second argument will throw with an empty array. Normally this should not be a problem, since you want to display a custom message saying something like 'this is empty' for empty arrays anyway.
Update for Typescript
You can use this in Typescript (without type-unsafe any
) with a React.ReactNode
type parameter on .map()
:
class List extends React.Component {
render() {
<div>
{this.props.data
.map<React.ReactNode>(t => <span>{t}</span>)
.reduce((prev, curr) => [prev, ', ', curr])}
</div>
}
}
You can use reduce
to combine multiple elements of an array:
React.createClass({
render() {
<div>
this.props.data
.map(t => <span>t</span>)
.reduce((accu, elem) => {
return accu === null ? [elem] : [...accu, ',', elem]
}, null)
</div>
}
})
This initializes the accumulator with null, so we can wrap the first item in an array. For each following element in the array, we construct a new array that contains all previous elements using the ...-operator
, add the separator and then the next element.
Array.prototype.reduce()
If I just want to render a comma-separated array of components, I usually find reduce
too verbose. A shorter solution in such cases is
{arr.map((item, index) => (
<Fragment key={item.id}>
{index > 0 && ', '}
<Item {...item} />
</Fragment>
))}
{index > 0 && ', '}
will render a comma followed by a space in front of all array items except the first one.
If you want to separate the second-to-last item and the last one by something else, say the string ' and '
, you can replace {index > 0 && ', '}
with
{index > 0 && index !== arr.length - 1 && ', '}
{index === arr.length - 1 && ' and '}