React로 본격적인 프로젝트를 만들어본게 처음이다보니 미흡한 부분이 많았다.
자유게시판 Detail 페이지에 노출되는 정보는 다음과 같다.
1. 글 정보
- 제목
- 내용
2. 작성자 정보
- 작성자 아이디
- 작성자 프로필
3. 댓글, 대댓글 정보
- 작성자 아이디
- 작성자 프로필
불러올 정보가 많다보니 처음 무턱대고 짠 쿼리(?) 문으로 실행 해 봤더니 세상에
댓글,대댓글 까지 모드 랜더링 되는데 3초가 넘는 시간이 걸리기 시작했다.
# 해당 코드
// 댓글 조회 함수
const getComment = async () => {
try {
const res = await axios.get(`http://localhost:8088/comment/commentList?postId=${id}`);
let commentsWithMemberInfo = await Promise.all(
res.data.comment.map(async (comment) => {
const writerInfoResponse = await axios.get(
`http://localhost:8088/member/memberSearching?nickname=${comment.writer}`
);
comment.writerInfo = {
class: writerInfoResponse.data.member.class,
profileImg: writerInfoResponse.data.member.profileImg,
};
if (comment.reComment) {
comment.reComment = await Promise.all(
comment.reComment.map(async (reComment) => {
const reWriterInfoResponse = await axios.get(
`http://localhost:8088/member/memberSearching?nickname=${reComment.writer}`
);
reComment.writerInfo = {
class: reWriterInfoResponse.data.member.class,
profileImg: reWriterInfoResponse.data.member.profileImg,
};
return reComment;
})
);
}
return comment;
})
);
console.log("commentsWithMemberInfo 내용물 : ", commentsWithMemberInfo);
const sortedComments = commentsWithMemberInfo.sort((a, b) => {
return new Date(a.createdAt) - new Date(b.createdAt);
});
setCommentList(sortedComments);
} catch (err) {
alert("통신에 실패했습니다.");
console.log(err);
}
};
몽고DB를 사용하고 있기 때문에 게시글 컬렉션에 댓글, 대댓글 까지 들어있는 구조를 가지고 있다.
하지만 게시글의 댓글 정보에는 작성자 id와 댓글 내용에 관한 정보밖에 담겨있지 않다.
문제는 화면에 노출시켜야 하는 정보에는 작성자의 프로필 이미지까지 있다는점이었다,.
처음엔 그냥 무턱대고 다 긁어왔다.
게시글 id를 통해 해당 게시글에 있는 댓글 작성자들의 id정보를 가져오고
그 정보를 map함수를 돌려 Back단과 통신해 회원정보 컬렉션에서 작성자들의 정보를 모두 긁어와 프로필 이미지를 출력시켰다.
이 방식으로 구현했더니 한 페이지를 랜더링하는데 3초가 넘는 시간이 걸렸다.
이건 아니다 싶어 구글링과 챗gpt를 통해 속도를 개선해나가기 시작했다.
다음이 그 결과물이다
# Front
// 댓글 조회 함수
const getComment = () => {
console.time('소요시간');
axios.get(`http://localhost:8088/comment/commentList2?postId=${id}`)
.then((res) => {
setCommentList(res.data.comments)
console.timeEnd('소요시간');
})
}
/* 작성자 정보 뭉탱이로 가져가서 받아오기 */
const getWriter = async () => {
const obj = {};
commentList.forEach(comment => {
if (!obj[comment.writer]) {
obj[comment.writer] = true;
}
if (comment.reComment) {
comment.reComment.forEach(reComment => {
if (!obj[reComment.writer]) {
obj[reComment.writer] = true;
}
});
}
});
const writers = Object.keys(obj);
try {
const response = await axios.post('http://localhost:8088/member/getWriterInfo', { writers });
const writerInfoArray = response.data.writerInfoArray;
console.log('작성자 정보:', writerInfoArray);
setWriterInfoArray(writerInfoArray);
} catch (error) {
console.error(error);
}
};
useEffect(() => {
getWriter();
}, [commentList]); */
# Back
// 새로운 조회함수
router.get('/commentList2', async (req, res) => {
console.time('소요시간');
const postId = req.query.postId;
try {
console.log('댓글 리스트 도착', postId);
// 댓글 및 대댓글 작성자 닉네임 모음
const writerNicknames = [];
const comments = await Comment.find({ postId: postId });
// 댓글 작성자 닉네임 수집
comments.forEach(comment => {
if (comment.writer) {
writerNicknames.push(comment.writer);
}
if (comment.reComment) {
comment.reComment.forEach(reComment => {
if (reComment.writer) {
writerNicknames.push(reComment.writer);
}
});
}
});
// 작성자 정보 일괄 조회
const writerInfos = await Member.find({ nickname: { $in: writerNicknames } });
const getWriterInformation = comments.map(comment => {
const writerInfo = writerInfos.find(info => info.nickname === comment.writer);
if (comment.reComment) {
comment.reComment.forEach(reComment => {
const reWriterInfo = writerInfos.find(info => info.nickname === reComment.writer);
reComment.writerInfo = reWriterInfo.toJSON();
});
}
return {
...comment.toJSON(),
writerInfo: writerInfo.toJSON(),
};
});
res.json({ comments: getWriterInformation });
} catch (err) {
console.log(err);
res.json({ message: false });
}
console.timeEnd('소요시간');
})
맨 처음 구현한 방식은 Front단과 Back단을 map함수를 통해 계속 돌리는 구조였다.
처음 Java와 JDBC, mybatis를 배웠을 때 DB와 연결할 때 리소스 소모가 커 미리 connection pool을 만들어 두는게 생각이 나서
Front와 Back을 여러번 왔다갔다 하지말고 한번만 통신해도 되도록 데이터를 정제하는 방법으로 구현을 했다.
조회 쿼리문도 mongoDB 공식문서를 통해 더 나은 쿼리문으로 개선을 했다.
https://www.mongodb.com/docs/manual/reference/operator/query/in/
$in — MongoDB Manual
Docs Home → MongoDB Manual $inThe $in operator selects the documents where the value of a field equals any value in the specified array.You can use $in for deployments hosted in the following environments:MongoDB Atlas: The fully managed service for Mong
www.mongodb.com
개선 결과 페이지의 모든 정보를 랜더링하는데 걸리는 평균 시간이 0.3초로 단축되었다!
'프로젝트 코드리뷰 > ITTY' 카테고리의 다른 글
익명 댓글 인덱싱 (0) | 2024.02.13 |
---|---|
FireBase 이미지 호스팅 (React, Quill) (0) | 2023.11.21 |
리액트 스와이프(드래그 스크롤) 기능구현 (0) | 2023.11.21 |