How to render react components by using map and join?

I have one component which is going to display Array of String. The code looks like this:

React.createClass({
  render() {
     <div>
        this.props.data.map(t => <span>t</span>)
     </div>
  }
})

It is working perfectly fine. i.e. if props.data = ['tom', 'jason', 'chris'], the rendered result in the page would be tomjasonchris.

Then, I want to join all the names by using comma, so I change the code to:

this.props.data.map(t => <span>t</span>).join(', ')

However, the rendered result is [Object], [Object], [Object].

I don't know how to interpret object to become react components to be rendered. Any suggestion?


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()


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 ]);