user4759415
user4759415

Reputation:

Loop through array in React and create elements (not list items) from it

I'm learning React and have done a fair bit of research on this. I've quickly discovered that the map() function is what I think I should be using for looping through an array.

But, my problem is all the examples in the React documentation and in the SO questions I've viewed use <ul> and <li> HTML elements to handle the output.

I'm not sure that my use case is "correct" as far as React structure is concerned, but, I want to output a <div> with some child elements each time I loop through.

Here is my static code so far:

const Comment = () => {
    return (
        <div className="commenter">
            <div className="commenter-inner">
                <div className="commenter-left">
                    <img src={chachi}/>
                    <p className="commenter-name">Scott Baio</p>
                </div>            
                <div className="commenter-comment">
                    <p>Ehhhh!! Joanie loves Chachi!!!</p>
                </div>
            </div>
        </div> 
    )
  }

This works, but now if I have additional comments I want to be able to serve up the same block of code again but with the new commenters name, image, comment content etc.

So I've now made an array to house my multiple commenters, and things aren't really working anymore.

import React, { Component } from 'react'
import fonzie from "./img/the-fonz.jpg";
import chachi from "./img/chachi.jpg";
    
const Comments = [
    {
        id: 1, 
        name: 'Hello World', 
        photo: fonzie,
        comment: 'Welcome to learning React!'
    },
    {
        id: 2, 
        name: 'Hello World', 
        photo: chachi,
        comment: 'Welcome to learning React!'
    }    
  ];


const commentEngine = props.Comments.map((comment) =>   

    <div className="commenter" key={comment.id}>
        <div className="commenter-inner">
            <div className="commenter-left">
                <img src={comment.photo}/>
                <p className="commenter-name">{comment.name}</p>
            </div>            
            <div className="commenter-comment">
                <p>{comment.comment}</p>
            </div>
        </div>
    </div> 
  );

class Comments extends Component {
    render() {
        return (
        <div className="comments-section col-md-10 offset-md-1 col-sm-12">   
            <h4>Comments</h4>
            <commentEngine />
        </div>    
        );
    }
  }



export default Comments

At this point I'm unsure how to verify if my loop is working in the first place and how to get the output properly displaying in my app.

Any help is greatly appreciated, as is insight into whether or not this is well structured or should be separate components.

Thanks!

Upvotes: 0

Views: 273

Answers (3)

Rohan Agarwal
Rohan Agarwal

Reputation: 2609

const commentEngine = (comments) => {   
    return comments.map((comment)=>{
         return (
          <div className="commenter" key={comment.id}>
          <div className="commenter-inner">
            <div className="commenter-left">
                <img src={comment.photo}/>
                <p className="commenter-name">{comment.name}</p>
            </div>            
            <div className="commenter-comment">
                <p>{comment.comment}</p>
            </div>
          </div>
         </div> 
  )})

class Comments extends Component {
    render() {
        return (
        <div className="comments-section col-md-10 offset-md-1 col-sm-12">   
            <h4>Comments</h4>
            {commentEngine(props.Comment)}
        </div>    
        );


    }
  }

Now when you render Comments you need to pass the Comment props.

<Comments Comment={Comments}/>

Upvotes: 1

Stark Jeon
Stark Jeon

Reputation: 1145

USAGECASE

import React, { Component } from 'react'
import fonzie from "./img/the-fonz.jpg";
import chachi from "./img/chachi.jpg";
    
const Comments = [
    {
        id: 1, 
        name: 'Hello World', 
        photo: fonzie,
        comment: 'Welcome to learning React!'
    },
    {
        id: 2, 
        name: 'Hello World', 
        photo: chachi,
        comment: 'Welcome to learning React!'
    }    
  ];


const Comment = props =>
    const {comment} = props;
    <div className="commenter" key={comment.id}>
        <div className="commenter-inner">
            <div className="commenter-left">
                <img src={comment.photo}/>
                <p className="commenter-name">{comment.name}</p>
            </div>            
            <div className="commenter-comment">
                <p>{comment.comment}</p>
            </div>
        </div>
    </div> 
  );

class Comments extends Component {
    render() {
        return (
        <div className="comments-section col-md-10 offset-md-1 col-sm-12">   
            <h4>Comments</h4>
            {Comments.map((comment,index) => <Comment key={'[CUSTOM_KEY]'} props={comment}> )}
        </div>    
        );
    }
  }



export default Comments

ANSWER

  1. First of all, You can use index parameter in Array.map
  2. Secondly, if you want to use list component you can make Single Component like <Comment comment={comment}> and you can use it with Array.map
  3. And It is very good to study How to make functional component

Upvotes: -1

cbr
cbr

Reputation: 13642

It sounds like you want to re-use the Comment component with data passed by Comments. In React, this is done via props.

So, you'll want to pass the images's src, the name, and the description:

const comments = [
  {
    id: 1,
    name: "Hello World",
    photo: fonzie,
    comment: "Welcome to learning React!",
  },
  {
    id: 2,
    name: "Hello World",
    photo: chachi,
    comment: "Welcome to learning React!",
  },
];

class Comments extends Component {
  render() {
    return (
      <div className="comments-section col-md-10 offset-md-1 col-sm-12">
        <h4>Comments</h4>
        {comments.map((comment) => {
          return (
            <Comment
              key={comment.id} // https://reactjs.org/docs/lists-and-keys.html
              name={comment.name}
              imgSrc={comment.photo}
              comment={comment.comment}
            />
          );
        })}
      </div>
    );
  }
}

Notice that I've renamed the constant array Comments to comments so that the name doesn't clash with the Comments component.

Then in the Comment component, you can access these props via the argument passed to the function component:

const Comment = (props) => {
  return (
    <div className="commenter">
      <div className="commenter-inner">
        <div className="commenter-left">
          <img src={props.imgSrc} />
          <p className="commenter-name">{props.name}</p>
        </div>
        <div className="commenter-comment">
          <p>{props.comment}</p>
        </div>
      </div>
    </div>
  );
};

Additionally, we can make the code a bit less verbose by leveraging object destructuring:

class Comments extends Component {
  render() {
    return (
      <div className="comments-section col-md-10 offset-md-1 col-sm-12">
        <h4>Comments</h4>
        {comments.map(({ id, name, photo, comment }) => {
          return (
            <Comment key={id} name={name} imgSrc={photo} comment={comment} />
          );
        })}
      </div>
    );
  }
}

// ...

const Comment = ({ imgSrc, name, comment }) => {
    return (
      <div className="commenter">
        <div className="commenter-inner">
          <div className="commenter-left">
            <img src={imgSrc} />
            <p className="commenter-name">{name}</p>
          </div>
          <div className="commenter-comment">
            <p>{comment}</p>
          </div>
        </div>
      </div>
    );
  };

Upvotes: 1

Related Questions