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.
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?
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; 

