중첩된 UI를 랜더링하기 위한 아코디언 컴포넌트 개발 과정에 대해 작성해보려한다.
UI
: 대댓글이 있는 경우, 댓글에 버튼을 출력하고 버튼 클릭 시 대댓글이 아래로 펼쳐짐
- 댓글 - 대댓글 input - 대댓글이 한 세트로 나타나야하는 구조
- Accordian 컴포넌트에서 조건부 스타일 구현 (대댓글에 존재여부에 따라)
- stack: React, SCSS, classnames
구현 결과
구현 과정
- 상위 컴포넌트에서 API 응답으로 댓글
객체가 담긴 배열
을 map method를 통해 accordian 컴포넌트 return
// accordian의 상위 컴포넌트
{reviews &&
reviews.map((review) => {
return (
<Accordion
review={review}
key={review.id}
movieId={id}
fetchReviews={fetchReviews}
/>
);
})}
JSX 구조
button, 대댓글 리스트(article)가 나란히 있는 구조
// accordian.js
...
<댓글 Component />
<대댓글 input />
// 편의상 accordian 부분만 기재
<>
// button UI: 댓글 개수 ▼
<button
className={cx(styles.showCommentsButton, {
[styles.isShow]: isClicked,
})}
onClick={() => setIsShow((cur)=> !cur)}
>
댓글 {review.comments.length}
<ChevronUp /> // SVG
</button>
// 대댓글 list
<article className={styles.commentWrap}>
{review.comments.map((comment) => {
return (
<Comment />
})}
</article>
</>
CSS
댓글 버튼의 state에 따라 대댓글 container를 보여주도록 구현
// 댓글 드롭다운 버튼
.showCommentsButton {
@include m.flex();
padding: 0 0 16px 16px;
font-size: 16px;
> svg {
transition: transform 0.3s ease-in-out;
}
// 버튼이 isShow class를 가질 때
// = 버튼이 눌려진 상태(state)일 때
&.isShow {
> svg {
transform: rotate(0deg);
}
// 버튼 옆에 존재하는 대댓글 list 보여주기
& + .commentWrap {
visibility: visible;
max-height: 100vh;
}
}
}
// 대댓글 Container
.commentWrap {
transition: max-height 0.3s ease-in-out, visibility 0.3s ease-in-out;
visibility: hidden;
max-height: 0px;
overflow-y: scroll;
}
- 검색 결과 배열이 존재할 경우, grid를 활용하여 출력되는 컴포넌트를 반응형으로 나열.
- 검색 결과가 없거나 loading 상태에 따라 상이한 UI 출력
- 영화 카드에 hover 시, overlay를 출력하여 별점과 영화 제목 출력하고, 카드가 위로 움직이며 커지는 애니메이션 추가
&:hover {
transform: scale(1.1) translateY(-10px);
> .overlay {
background-color: c.$C_BLACK_50;
visibility: visible;
}
}