위 사진은 클론코딩을 진행한 클래스101의 클래스 상세페이지이다.
각각의 탭을 클릭하면 해당하는 위치로 이동을 하는데 처음에는 바로 화면이 바뀌길래 active tab인줄 알았다. 클론코딩을 진행하면서 이 부분이 조금 불편하다고 생각되어서 스크롤 이동을 부드럽게 만들어주었다. 각 탭에 해당하는 element는 각자 ref를 가지고 있었고 이동을 하려면 하나씩 ref를 만들어주어야 했다.
하지만 똑같은 기능을 하는 함수를 여러개 만드는것이 별로 마음에 들지 않았기 때문에 클릭할 때 마다 동적으로 바뀌는 ref를 만들고 싶었다. 그래서 ref를 배열로 선언하여 클릭할 때 마다 해당하는 ref를 찾아가도록 만들었다.
그런데 문제가 있었다. 처음 클릭을 하면 제대로 동작을 했으나 그 뒤로는 바뀌지 않았다. ref가 고정이 되어서 변하지 않았다. 그래서 1차 프로젝트때 썼던 맵핑을 이용해 각각의 탭에 value를 주고 객체를 생성하여 임의의 index를 주었다.
const focusTarget = useRef([]);
const scrollToRef = (value) => {
const obj = {
PREVIEW: 0,
CURRICULUM: 1,
PACKAGE: 2,
DELIVERY: 3,
BENEFIT: 4,
CREATOR: 5,
RECOMMEND: 6,
REFUND: 7,
};
focusTarget.current[obj[value]].scrollIntoView({ behavior: "smooth" });
};
위 함수는 해당하는 ref로 이동하는 함수이고 각각의 탭에 onClick으로 묶여있다.
<Tabs
value={currentValue}
theme={Theme.dark}
type="red"
className="detailHeader"
onChange={handleChange}
>
{tabItems.map((el, i) => {
return (
<Tabs.Item
value={el.value}
title={el.title}
key={i}
onClick={scrollToRef}
/>
);
})}
</Tabs>
각각의 탭의 부모에 걸려있는 onChange함수는 다음과 같다.
const handleChange = (value) => {
setCurrentValue(value);
scrollToRef(value);
};
클릭 시 탭의 색깔이 바뀜과 동시에 해당하는 ref로 이동을 한다.
각각의 탭의 최상단에 위치한 element에는 다음와 같이 ref가 선언되었다.
<div className="productViewBox" ref={(el) => (focusTarget.current[0] = el)}>
ref 배열의 index를 인식하지 못해서 맵핑해놓은 객체의 키값을 인식하도록 만들었고 결과적으로 정상작동을 하였다.
스크롤을 오르고 내릴 때 마다 탭 색깔이 바뀌는것도 구현하고 싶었으나 여기서 막히고 말았다.
이렇게 접혀있다가 더보기를 누르는 순간
늘어나는 곳이 있는데 처음에는 각 element의 scrollTop 위치를 계산해서 어느정도 구현을 했다. 하지만 화면이 커지거나 이처럼 element의 길이가 늘어나는 경우는 대처하지 못했다. 모든 경우에 맞춰 scrollTop을 구해주고 싶었지만 그렇게 하면 코드가 너무 지저분해져서 어쩔수 없이 포기하고 말았다. Intersection Observer API를 이용하여 해당 ref를 지나가는지 여부도 판단해보려고 했지만 observe 자체가 되질 않아서 포기했다. 어떤식으로 구현을 했는지 정말 궁금하다.