DEV Community

Cover image for Comment Section in React Native
RamR
RamR

Posted on • Updated on

Comment Section in React Native

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,
  }
Enter fullscreen mode Exit fullscreen mode

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',
  }, 
];
Enter fullscreen mode Exit fullscreen mode

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>
  );
Enter fullscreen mode Exit fullscreen mode

Image description

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>
    );
  };

. . .

Enter fullscreen mode Exit fullscreen mode

Image description

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',
  }, 
];
Enter fullscreen mode Exit fullscreen mode

Image description

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}
      />
  . . .
  );

Enter fullscreen mode Exit fullscreen mode

Image description

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);
  }, []);

Enter fullscreen mode Exit fullscreen mode

Image description

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>
    );
  };

. . .
Enter fullscreen mode Exit fullscreen mode

Image description

Hope now you got it, why we used property type 0, 1, 2

The Result

After adding some mock data , the comment section page

Image description

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)