youngst
Young St_____
youngst
  • 분류 전체보기 (30)
    • Dev (28)
      • JS Family, HTML, CSS (14)
      • Git & Github (0)
      • Projects (7)
      • else (5)
      • TIL (2)
    • 일상 (2)
      • 그냥 글 (1)
      • 사과 농장에서 살아남기 (1)

인기 글

태그

  • ReactRouter
  • Vite
  • styled-components
  • JSEvent
  • TypeScript
  • 프론트엔드스쿨
  • JavaScript
  • CloneCoding
  • 제로베이스스쿨
  • Next.js
  • Firebase
  • react-router
  • 제로베이스
  • vscode
  • 후기
  • 옥소폴리틱스
  • GitHub-Page
  • 공부내용정리
  • jsdoc
  • React

티스토리

hELLO · Designed By 정상우.
youngst

Young St_____

[옥소폴리틱스 인턴십] 옥소폴리틱스 메인 페이지 클론 코딩 (2)
Dev/Projects

[옥소폴리틱스 인턴십] 옥소폴리틱스 메인 페이지 클론 코딩 (2)

2022. 8. 8. 00:25

 

베스트 댓글 영역 구현

그룹 영역은 사실 구현해야 할 부분이 많이 없었기 때문에 커뮤니티 영역을 맡은 팀원분을 도와 '베스트 댓글' 항목의 구현을 내가 맡기로 하였다.

커뮤니티 글 하단의 댓글 영역이 있다

 

옥소폴리틱스의 베스트 댓글은 조금 특이하게 조회수 순으로만 베스트 댓글을 선정하는 것이 아니라 각 '부족'별로 베스트 댓글을 하나씩 보여주는 방식을 사용하고 있다. 이를 통해 각 부족 간의 의견을 모두 보여줄 수 있다.

 

옥소폴리틱스로부터 구현을 위해 제공된 데이터는 해당 게시글의 전체 댓글 데이터와 전체 게시글의 베스트 댓글 ID가 들어있는 데이터를 각각 JSON 파일로 받았다.

 

bestCommentIds.json

 

comments.json

내가 해야 할 일은 각 게시글의 베스트 댓글 ID들을 입력하여 comments.json에서 해당 댓글들을 찾아 출력하면 되는 일이었다. json 파일을 받는 것은 그룹 영역에서와 마찬가지로 fetchJsonToArray 함수를 사용하면 되었기 때문에 utils 폴더에 따로 함수를 만들어 사용하였다.

//# fetchJsonToArray.js

function fetchJsonToArray(rawJson) {
  const array = [];
  const jsonData = rawJson.data;
  for (const key in jsonData) {
    jsonData[key] = { ...jsonData[key], id: key };
    array.push(jsonData[key]);
  }

  return array;
}

export default fetchJsonToArray;

 

PostComments 영역 구성

댓글 영역은 다음과 같이 3 부분으로 나누어 구현하였다.

  • <CommentsHeader /> - 댓글 수 출력
  • <CommentsArea /> - 베스트 댓글 영역
  • <Comment /> - 댓글 구현 컴포넌트(CommentsArea의 자식 컴포넌트)
function PostComments({ postID, commentsNum }) {
  return (
    <Container>
      <CommentsHeader commentsNum={commentsNum} />
      {commentsNum > 0 ? <CommentsArea postID={postID} /> : null}
    </Container>
  );
}

 

Comments Header

댓글의 Header 영역은 전체 댓글 수를 표시해주고 클릭 시 전체 댓글을 볼 수 있는 페이지를 띄워주었다. 하지만 이번 클론 코딩에서 전체 댓글의 ID는 제공되지 않았기 때문에, 클릭 시 전체 댓글 수를 표시해주는 것으로 갈음하였다. 전체 댓글 수를 위해 조상 컴포넌트인 Post로부터 댓글 수를 props로 받아왔다.

const CommentsHeader = ({ commentsNum }) => {
  return (
    <Header onClick={() => alert(`댓글 ${commentsNum}개`)}>
      댓글 {commentsNum}
      {' >'}
    </Header>
  );
};

 

Comments Area

베스트 댓글은 bestCommentIds.json 파일을 통해 목록을 받고 이를 이용해 comments.json에서 정보를 받아 출력하였다. 해당 게시글의 ID는 부모 요소인 Post로부터 받았다(postID).

const CommentsArea = ({ postID }) => {
  const bests = bestCommentIds.data[postID];
  const comments = commentsJson.data;
  const commentsArr = [];

  for (const key in bests) {
    commentsArr.push(comments[bests[key]]);
  }
  // console.log(commentsArr);

  return (
    <Container>
      {commentsArr.map((elem, idx) => (
        <Comment
          key={idx}
          answer={elem.answer}
          comment={elem.comment}
          userTribeId={elem.userTribeId}
        />
      ))}
    </Container>
  );
};

 

Comment 구현

데이터를 모두 받았기 때문에 comment 컴포넌트는 간단할 것이라 생각했지만 그렇지 않았다. 우선 댓글 내용의 길이를 적당이 재단하여 보여줘야 했다. CSS의 overflow: hidden을 이용하는 방법도 있었으나 그냥 간단하게 slice를 이용해 길이를 잘라주었다.

  const commentText =
    comment.length > 55 ? comment.slice(0, 54) + '...' : comment;

다른 문제는 각 베스트 댓글마다 응답과 부족 이미지를 띄워주어야 한다는 것이었다. 옥소폴리틱스의 부족은 총 5 종류이고 응답은 4 종류(O, X, 중립, 무응답)였기 때문에 총 20가지의 이미지 파일 중에 조건에 맞는 이미지를 골라주어야 했다. 처음에는 모든 이미지를 import 해야 하나 생각했으나 이건 아닌 거 같아 다른 방법을 생각해보았다.

 

각 부족 이름이 number로 제공되고 응답이 4가지로 고정인 것에서 착안하여 배열과 객체를 이용한 다음과 같은 로직으로 이미지 파일을 보여줄 수 있게 하였다. 이미지들은 public 폴더 안에 넣어 절대 경로를 이용하기 쉽게 해 주었다.

// getTribeImg.jsx

import React from 'react';

const getTribeImg = (ans, tribeID) => {
  ans = ans ? ans : 'u';
  let tribes = [null, 'tiger', 'hippo', 'elephant', 'dino', 'lion'];
  let answer = {
    o: 'O',
    x: 'X',
    '?': 'DUNNO',
    u: 'NORMAL',
  };

  return (
    <img
      src={`/img/tribes/${
        tribes[parseInt(tribeID)]
      }_${answer[ans]}.png`}
    />
  );
};

export default getTribeImg;

 

// Comment.jsx

const Comment = ({ answer, comment, userTribeId }) => {
  const commentText =
    comment.length > 55 ? comment.slice(0, 54) + '...' : comment;
  return (
    <Container>
      <div className='tribeImg'>{getTribeImg(answer, userTribeId)}</div>
      <div className='commentText'>{commentText}</div>
    </Container>
  );
};

export default Comment;

 

회고

각 팀원들이 맡은 부분을 모두 조립하여 push한 결과 몇 가지의 사소한... 충돌이 있었지만 잘 해결하였다. 코딩 공부를 시작하고 사실상 처음 해 본 프로젝트였지만 팀원분들과 호흡이 너무 잘 맞았고, 요소들이 설계한 대로 딱딱 맞아 동작할 때는 희열까지 느껴졌다!

 

옥소폴리틱스의 멘토분들께서도 처음 해본 프로젝트인데 놀라운 퍼포먼스라며 칭찬해주셨다. 다음에 시작하게 될 프로젝트도 너무 기대된다!

저작자표시 비영리 변경금지 (새창열림)

'Dev > Projects' 카테고리의 다른 글

[옥소폴리틱스 인턴십] 옥소폴리틱스 FAQ 페이지 구현하기 (2)  (0) 2022.08.20
[옥소폴리틱스 인턴십] 옥소폴리틱스 FAQ 페이지 구현하기 (1)  (0) 2022.08.19
[Cloning] (Nomad Code) Twitter clone code with Firebase & React (2) - Firestore, Firebase storage, FileReader API  (0) 2022.08.14
[Cloning] (Nomad Code) Twitter clone code with Firebase & React (1) - Firebase, React Router, Vice 최신 버전으로 사용하기  (2) 2022.08.11
[옥소폴리틱스 인턴십] 옥소폴리틱스 메인 페이지 클론 코딩 (1)  (2) 2022.08.06
    'Dev/Projects' 카테고리의 다른 글
    • [옥소폴리틱스 인턴십] 옥소폴리틱스 FAQ 페이지 구현하기 (1)
    • [Cloning] (Nomad Code) Twitter clone code with Firebase & React (2) - Firestore, Firebase storage, FileReader API
    • [Cloning] (Nomad Code) Twitter clone code with Firebase & React (1) - Firebase, React Router, Vice 최신 버전으로 사용하기
    • [옥소폴리틱스 인턴십] 옥소폴리틱스 메인 페이지 클론 코딩 (1)
    youngst
    youngst
    좋은 프론트엔드 개발자가 되고 싶습니다

    티스토리툴바