0

I'm trying to create a comment widget in React. I have the data below:

const data = [ { id: 1, comment: "Test Comment" }, { id: 2, comment: "Second Comment", subComments: [ { comment: "Sub second comment 1" }, { comment: "Sub second comment 2" }, { comment: "Sub second comment 3" } ] }, { id: 3, comment: "How much is 2 + 2?", subComments: [ { comment: "It is 5", subComments: [ { comment: "No, it's 4." } ], }, { comment: "4!", }, { comment: "Is this a joke?" } ] } ] 

Then, I create the React app below. I have access to the data array in the component.

import React, {useEffect, useState} from 'react'; const Comment = () => { const [ comments, setComments ] = useState([]) useEffect(() => { setComments(data); }, []); const showSubComments = (subComments) => { if(subComments.length === 0) return; subComments.map((obj, index) => { return ( <> <br /> <span style={{marginLeft: '2rem'}}>{obj.comment}</span> {showSubComments(obj.subComments || [])} </> ) }); } return ( <> <div> <textarea type="textarea" rows={5} cols={50} /> <div> {comments.map((obj, index) => { return ( <p key={index}> {obj.comment} {showSubComments(obj.subComments || [])} </p> ) })} </div> </div> </> ); } export default Comment; 

It's not listing the subComments, just the comments. Why? The showSubComments() method should be returning the data recursively.

enter image description here

Changing the code to have a Map to easily access the subcomments in order to edit or delete them. As you can see in the image below, now the third comment 4! is displaying in the correct level with the left-margin. Does anyone know why it is happening?

enter image description here

import React, {useEffect, useState, useMemo} from 'react'; const data = [ { id: 1, comment: "Test Comment" }, { id: 2, comment: "Second Comment", subComments: [ { comment: "Sub second comment 1" }, { comment: "Sub second comment 2" }, { comment: "Sub second comment 3" } ] }, { id: 3, comment: "How much is 2 + 2?", subComments: [ { comment: "It is 5", subComments: [ { comment: "No, it's 4." } ], }, { comment: "4!", }, { comment: "Is this a joke?" } ] } ] const Comment = () => { const [ comments, setComments ] = useState([]); const [ subComments, setSubComments ] = useState(new Map()); const [ commentText, setCommentText ] = useState(""); useEffect(() => { const commentsArr = []; const subCommentsMap = new Map(); const setSubCommentsMap = (key, arr) => { if(arr === undefined) return; subCommentsMap.set(key, [...arr]); for(let i=0; i<arr.length; i++) { const newKey = `${key},${i}`; setSubCommentsMap(newKey, arr[i].subComments) } } for(let i=0; i<data.length; i++) { commentsArr.push(data[i].comment); let subComments = data[i].subComments; let key = i.toString(); setSubCommentsMap(key, subComments) } setComments(commentsArr); setSubComments(subCommentsMap); }, []); const displayComments = useMemo(() => { const displaySubComments = (subCommentsArr, margin) => { return subCommentsArr.map((obj, index) => { return ( <span key={index} style={{marginLeft: `${margin}rem`, display: 'block'}}> {obj.comment} {displaySubComments(subComments.get(`${index.toString()},${index}`) || [], margin+2)} </span> ) }) } return comments.map((ele, index) => { return ( <div key={index}> <span> {ele} {displaySubComments(subComments.get(index.toString()) || [], 2)} </span> </div> ) }) }, [comments, subComments]) const handleTextOnChange = (event) => { setCommentText(event.target.value); } return ( <div> <div> <textarea type="textarea" value={commentText} onChange={handleTextOnChange} rows={5} cols={50} /> <button type="button">Add Comment</button> </div> <div> {displayComments} </div> </div> ) } export default Comment; 

2 Answers 2

1

You have forgotten to return after the map function

Try below:

 const showSubComments = (subComments) => { if (subComments.length === 0) return; return subComments.map((obj, index) => { return ( <div> <br /> <div style={{ marginLeft: "2rem" }}>{obj.comment}</div> <div style={{ marginLeft: "4rem" }}> {showSubComments(obj.subComments || [])} </div> </div> ); }); }; 

Just call the showSubComments with comments param

 return ( <> <div> <textarea type="textarea" rows={5} cols={50} /> <div>{showSubComments(comments)}</div> </div> </> ); 

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

I changed the code structure to use Map and for some reason my margin-left stop working
1

The problem is just about missing a single keyword return. You have tranformed subComments to react component, but you did not return to render them

return subComments.map((obj, index) => { return ( <> <br /> <span style={{marginLeft: '2rem'}}>{obj.comment}</span> {showSubComments(obj.subComments || [])} </> ) }); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.