Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to render react components by using map and join?

Tags:

reactjs

People also ask

How do you render a map in React?

In React, the map() function is most commonly used for rendering a list of data to the DOM. To use the map() function, attach it to an array you want to iterate over. The map() function expects a callback as the argument and executes it once for each element in the array.

How do you use a map in React components?

A map is a data collection type where data is stored in the form of key-value pairs. The value stored in the map must be mapped to the key. The map is a JavaScript function that can be called on any array. With the map function, we map every element of the array to the custom components in a single line of code.

Can you map components React?

Adding key to mapped elements This way, if a change is made to one of the items, React can know exactly which one to update. So mapped elements expect you to add a property called key to the element being repeated. You can choose anything that will help uniquely identify the element.


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

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 '}

The accepted answer actually returns an array of arrays because prev will be an array each time. React is smart enough to make this work, but is it is prone to causing problems in the future such as breaking Reacts diffing algorithm when giving keys to each result of map.

The new React.Fragment feature lets us do this in an easy to understand manner without the underlying issues.

class List extends React.Component {
  render() {
     <div>
        {this.props.data
          .map((t, index) => 
            <React.Fragment key={index}>
              <span> {t}</span> ,
            </React.Fragment>
          )
      </div>
  }
}

With React.Fragment we can simply place the separator , outside of the of the returned HTML and React won't complain.


the <span>{t}</span> you are returning is an object, not a string. Check the react docs about it https://facebook.github.io/react/docs/jsx-in-depth.html#the-transform

By using .join() on the returned array from map, you are joining the array of objects. [object Object], ...

You can put the comma inside the <span></span> so it gets rendered the way you want it to.

  render() {
    return (
      <div>
        { this.props.data.map(
            (t,i) => <span>{t}{ this.props.data.length - 1 === i ? '' : ','} </span>
          )
        }
      </div>
    )
  }

sample: https://jsbin.com/xomopahalo/edit?html,js,output