Reputation: 2381
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;
Upvotes: 0
Views: 347
Reputation: 13245
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>
</>
);
Upvotes: 1
Reputation: 12874
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 || [])}
</>
)
});
Upvotes: 1