Rendering an array.map() in React

JavascriptReactjs

Javascript Problem Overview


I am having a problem where I am trying to use array of data to render a <ul> element. In the code below the console.log's are working fine, but the list items aren't appearing.

var Main = React.createClass({
  getInitialState: function(){
    return {
      data: dataRecent
    }
  },

  render: function(){
    return (
      <div>
        <ul>
          {
           this.state.data.map(function(item, i){
             console.log('test');
             <li>Test</li>
           })
         }
        </ul>
      </div>
    )
  }
});

ReactDOM.render(<Main />, document.getElementById('app')); 

What am I doing wrong? Please feel free to point out anything that isn't best practice.

Javascript Solutions


Solution 1 - Javascript

Gosha Arinich is right, you should return your <li> element. But, nevertheless, you should get nasty red warning in the browser console in this case

> Each child in an array or iterator should have a unique "key" prop.

so, you need to add "key" to your list:

this.state.data.map(function(item, i){
  console.log('test');
  return <li key={i}>Test</li>
})

or drop the console.log() and do a beautiful oneliner, using es6 arrow functions:

this.state.data.map((item,i) => <li key={i}>Test</li>)

IMPORTANT UPDATE:

The answer above is solving the current problem, but as Sergey mentioned in the comments: using the key depending on the map index is BAD if you want to do some filtering and sorting. In that case use the item.id if id already there, or just generate unique ids for it.

Solution 2 - Javascript

You are not returning. Change to

this.state.data.map(function(item, i){
  console.log('test');
  return <li>Test</li>;
})

Solution 3 - Javascript

let durationBody = duration.map((item, i) => {
      return (
        <option key={i} value={item}>
          {item}
        </option>
      );
    });

Solution 4 - Javascript

Using Stateless Functional Component We will not be using this.state. Like this

 {data1.map((item,key)=>
               { return
                <tr key={key}>
                <td>{item.heading}</td>
                <td>{item.date}</td>
                <td>{item.status}</td>
              </tr>
                
                })}

Solution 5 - Javascript

You are implicitly returning undefined. You need to return the element.

this.state.data.map(function(item, i){
  console.log('test');
  return <li>Test</li>
})

Solution 6 - Javascript

Add up to Dmitry's answer, if you don't want to handle unique key IDs manually, you can use React.Children.toArray as proposed in the React documentation

React.Children.toArray

Returns the children opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice this.props.children before passing it down.

> Note: > > React.Children.toArray() changes keys to preserve the semantics of nested arrays when flattening lists of children. That is, toArray prefixes each key in the returned array so that each element’s key is scoped to the input array containing it.

 <div>
    <ul>
      {
        React.Children.toArray(
          this.state.data.map((item, i) => <li>Test</li>)
        )
      }
    </ul>
  </div>

Solution 7 - Javascript

I've come cross an issue with the implementation of this solution.

If you have a custom component you want to iterate through and you want to share the state it will not be available as the .map() scope does not recognize the general state() scope. I've come to this solution:

`

class RootComponent extends Component() {
    constructor(props) {
        ....
        this.customFunction.bind(this);
        this.state = {thisWorks: false}
        this.that = this;
    }
    componentDidMount() {
        ....
    }
    render() {
       let array = this.thatstate.map(() => { 
           <CustomComponent that={this.that} customFunction={this.customFunction}/>
       });
 
    }
    customFunction() {
        this.that.setState({thisWorks: true})
    }
}



class CustomComponent extend Component {

    render() {
        return <Button onClick={() => {this.props.customFunction()}}
    }
}

In constructor bind without this.that Every use of any function/method inside the root component should be used with this.that

Solution 8 - Javascript

Dmitry Brin's answer worked for me, with one caveat. In my case, I needed to run a function between the list tags, which requires nested JSX braces. Example JSX below, which worked for me:

{this.props.data().map(function (object, i) { return <li>{JSON.stringify(object)}</li> })}

If you don't use nested JSX braces, for example:

{this.props.data().map(function (object, i) { return <li>JSON.stringify(object)</li>})}

then you get a list of "JSON.stringify(object)" in your HTML output, which probably isn't what you want.

Solution 9 - Javascript

import React, { Component } from 'react';

class Result extends Component {

   
    render() {

           if(this.props.resultsfood.status=='found'){

            var foodlist = this.props.resultsfood.items.map(name=>{
                 
                   return (
                
                  
                   <div className="row" key={name.id} >
                   
                  <div className="list-group">   
                  
                  <a href="#" className="list-group-item list-group-item-action disabled">
                  
                  <span className="badge badge-info"><h6> {name.item}</h6></span>
                  <span className="badge badge-danger"><h6> Rs.{name.price}/=</h6></span>
                  
                  </a>
                  <a href="#" className="list-group-item list-group-item-action disabled">
                  <div className="alert alert-dismissible alert-secondary">
  
                    <strong>{name.description}</strong>  
                    </div>
                  </a>
                <div className="form-group">
                
                    <label className="col-form-label col-form-label-sm" htmlFor="inputSmall">Quantitiy</label>
                    <input className="form-control form-control-sm" placeholder="unit/kg"  type="text" ref="qty"/>
                    <div> <button type="button" className="btn btn-success"  
                    onClick={()=>{this.props.savelist(name.item,name.price);
                    this.props.pricelist(name.price);
                    this.props.quntylist(this.refs.qty.value);
                    }
                    }>ADD Cart</button>
                        </div>
                       
                       
                        
                  <br/>
                
                      </div>
                     
                </div>
               
                </div>
                      
                   )
            })
            
           
            
           }
         


        return (
<ul>
   {foodlist}
</ul>
        )
    }
}

export default Result;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser6542445View Question on Stackoverflow
Solution 1 - JavascriptDmitry BirinView Answer on Stackoverflow
Solution 2 - JavascriptGosha AView Answer on Stackoverflow
Solution 3 - JavascriptNajma MuhammedView Answer on Stackoverflow
Solution 4 - JavascriptazeemView Answer on Stackoverflow
Solution 5 - JavascriptDaniel A. WhiteView Answer on Stackoverflow
Solution 6 - JavascriptJee MokView Answer on Stackoverflow
Solution 7 - JavascriptRadu GalanView Answer on Stackoverflow
Solution 8 - Javascriptuser1258361View Answer on Stackoverflow
Solution 9 - JavascriptThilina ImalkaView Answer on Stackoverflow