lets design a simple comment section UI in React Native.
Contents
- sample data
- page structure
- design simple comment item
- add child comments data
- form array to design child comments
- form array to design grand child comments
- margin adjustment
- the result
Sample Data
Lets assume the JSON object response from the server like this
{
id: // id,
parent_id: // parent comment id,
name: // commenting person name,
image: // commenting person image,
text: // comment text,
}
and the sample data like this
const list_comments = [
{
id: '1',
parent_id: '0',
name: 'david',
image: '',
text: 'this is parent cooment 1',
},
{
id: '2',
parent_id: '0',
name: 'kumar',
image: '',
text: 'this is parent cooment 2',
},
{
id: '3',
parent_id: '0',
name: 'selva',
image: '',
text: 'this is parent cooment 3',
},
];
Page structure
Basically we have 3 main components in this page. Title, Comments List (FlatList) and Comment List Item.
const renderItem = ({ item }) => {
return <Text>{item.text}</Text>;
};
return (
<View style={styles.container}>
<Text style={styles.text}>Comments {listComment.length}</Text>
<FlatList
style={{ marginTop: 5 }}
data={list_comments}
renderItem={renderItem}
keyExtractor={(item, index) => '_cmt_item' + index}
/>
</View>
);
Design simple comment item
With this basic structure, lets start designing the comment item component
. . .
const renderItem = ({ item }) => {
return <CommentItem comment={item} />;
};
const CommentItem = ({ comment }) => {
return (
<View style={styles.commentItem}>
<ProfilePic letter={comment.name[0]} />
<View style={{ marginLeft: 10, flex: 1 }}>
<Text style={styles.commentBy}>{comment.name}</Text>
<Text style={styles.commentText}>{comment.text}</Text>
</View>
</View>
);
};
const ProfilePic = ({ letter = '' }) => {
return (
<View style={styles.profileImg}>
<Text style={styles.profileText}>{letter.toUpperCase()}</Text>
</View>
);
};
. . .
Add child comments data
const list_comments = [
// . . .
{
id: '4',
parent_id: '1',
name: 'arul',
image: '',
text: 'this is c1 comment of p1',
},
{
id: '5',
parent_id: '1',
name: 'vinoth',
image: '',
text: 'this is c2 comment of p1',
},
{
id: '6',
parent_id: '2',
name: 'vishnu',
image: '',
text: 'this is c1 comment of p2',
},
];
Form array to design child comments
Now we need to restructure the array to render child comments below to the respective parent comment. For that, We have to sort out the array list in parent-child basis, then add a property which refers the type parent or child, that's the concept. Yes, We need a state variable obviously
const list_comments = [{
id: '1',
parent_id: '0',
name: 'david',
image: '',
text: 'this is parent cooment 1',
},
. . .
]
export default function App() {
const [listComment, setListComment] = useState([...list_comments]);
. . .
React.useEffect(() => {
// form object to render child
var arr = [];
var arr2 = [];
for (let item of list_comments) {
if (item.parent_id === '0') {
// new property type 0 parent comment
arr.push({ ...item, type: 0 });
arr2 = list_comments.filter((ele) => ele.parent_id === item.id);
if (arr2.length) {
// type 1 child comment
arr2 = arr2.map((ele) => ({ ...ele, type: 1 }));
arr = arr.concat(arr2);
}
}
}
setListComment(arr);
}, []);
return (
. . .
<FlatList
style={{ marginTop: 5 }}
data={listComment}
renderItem={renderItem}
keyExtractor={(item, index) => '_cmt_item' + index}
/>
. . .
);
Hope we understood the sorting approach.
Form array to design grand child comments
With the same approach, we are going to add grand child comments below to the child comment which is already below to the parent comment. Got it right? Two iterations and two filters going to be used. The Property type
refers parent(0), child(1) and grand child(2)
const list_comments = [
. . .
{
id: '7',
parent_id: '4',
name: 'martin',
image: '',
text: 'this is c1 comment of p1c1',
},
];
. . .
React.useEffect(() => {
// forming object to render grand child
var arr = [];
var arr2 = [],
arr3 = [];
for (let item of list_comments) {
if (item.parent_id === '0') {
arr.push({ ...item, type: 0 });
arr2 = list_comments.filter((ele) => ele.parent_id === item.id);
if (arr2.length) {
for (let item2 of arr2) {
arr3 = list_comments.filter((ele) => ele.parent_id === item2.id);
if (arr3.length) {
arr.push({ ...item2, type: 1 });
arr3 = arr3.map((ele) => ({ ...ele, type: 2 }));
arr = arr.concat(arr3);
} else {
arr.push({ ...item2, type: 1 });
}
}
}
}
}
setListComment(arr);
}, []);
Margin Adjustment
Margin adjustments like marginLeft and marginTop will give the proper comment section look.
Parent comment has more gap on top than the child comments. Also the grand child comment left side gap is 2 times bigger than the parent.
const comment_margin_left = 15;
export default function App() {
. . .
const CommentItem = ({ comment }) => {
return (
<View
style={[
styles.commentItem,
{
marginLeft: comment.type * comment_margin_left,
marginTop: comment.type === 0 ? 10 : 2,
},
]}>
<ProfilePic letter={comment.name[0]} />
<View style={{ marginLeft: 10, flex: 1 }}>
<Text style={styles.commentBy}>{comment.name}</Text>
<Text style={styles.commentText}>{comment.text}</Text>
</View>
</View>
);
};
. . .
Hope now you got it, why we used property type 0, 1, 2
The Result
After adding some mock data , the comment section page
Yeah, that's it. We are done!
Full source code available here
Thank you for reading this.
Thanks Everyone, thank you for everything and Thank you DEV.TO community
Top comments (0)