베스트 댓글 영역 구현
그룹 영역은 사실 구현해야 할 부분이 많이 없었기 때문에 커뮤니티 영역을 맡은 팀원분을 도와 '베스트 댓글' 항목의 구현을 내가 맡기로 하였다.
옥소폴리틱스의 베스트 댓글은 조금 특이하게 조회수 순으로만 베스트 댓글을 선정하는 것이 아니라 각 '부족'별로 베스트 댓글을 하나씩 보여주는 방식을 사용하고 있다. 이를 통해 각 부족 간의 의견을 모두 보여줄 수 있다.
옥소폴리틱스로부터 구현을 위해 제공된 데이터는 해당 게시글의 전체 댓글 데이터와 전체 게시글의 베스트 댓글 ID가 들어있는 데이터를 각각 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한 결과 몇 가지의 사소한... 충돌이 있었지만 잘 해결하였다. 코딩 공부를 시작하고 사실상 처음 해 본 프로젝트였지만 팀원분들과 호흡이 너무 잘 맞았고, 요소들이 설계한 대로 딱딱 맞아 동작할 때는 희열까지 느껴졌다!
옥소폴리틱스의 멘토분들께서도 처음 해본 프로젝트인데 놀라운 퍼포먼스라며 칭찬해주셨다. 다음에 시작하게 될 프로젝트도 너무 기대된다!