이력 홈페이지를 개발하던 중 친구에게 코멘트를 달아주기를 부탁하였고, 그 내용 중 여러 개의 명언이 슬라이드 되었으면 좋겠다는 조언(?)을 주었다!! 너무 고마웠고 이거 내가 직접 구현할 수 있겠는데? 라고 생각했다.
라이브러리를 사용하면 빠르게 구현할 수 있겠지만, 직접 구현해 보기로 한다.
1. 기능 나열
1. 매초마다 자동으로 슬라이드 된다.
2. 마지막에 도달하면 처음으로 돌아온다.
Banner에서 감명 깊었던 명언들을 자동 슬라이드 시킬 예정이라 네비게이션, 이전, 다음 버튼은 따로 구현하지 않는다. 추후에 요일에 따라 다른 명언들이 슬라이드 되도록 기능을 추가하면 재밌을 것 같다.
2. 리스트 Mock 데이터
[
{
id: 1,
quote: "사람들이 꿈을 이루지 못하는 한 가지 이유는 그들이 생각을 바꾸지 않고 결과를 바꾸고 싶어하기 때문이다",
author: "John Maxwell"
},
{
id: 2,
quote: "자신은 \"할 수 없다\"고 생각하는 동안 사실은 그것을 \"하기 싫다\"고 다짐하고 있는 것이다. 그러므로 실행되지 않는 것이다.",
author: "Baruch Spinoza"
},
{
id: 3,
quote: "지식은 보물이요. 실천은 보물상자를 여는 열쇠다. 보석이 아무리 가까이 있어도, 내가 팔을 뻗지 않으면 원하는 것을 얻을 수 없다.",
author: "노자"
},
{
id: 4,
quote: "손으로 10초면 충분히 할 수 있는 일을 컴퓨터로 하루 종일 프로그래밍해서 자동으로 수행할 때, 나는 더할 나위 없이 큰 행복을 느낀다.",
author: "Douglas Noel Adams"
},
]
3. AutoCount 기능
const [currentCount, setCurrentCount] = useState(1);
const [qutosList, setQutosList] = useState(quotesDummyData)
const countUpAndDown = useCallback(() => {
if (currentCount < qutesList.length - 1) {
setCurrentCount(currentCount + 1)
} else {
setCurrentCount(0);
}
}, [currentCount, qutesList]);
useEffect(() => {
let interval = setInterval(() => {
countUpAndDown();
}, 7000)
return () => { clearInterval(interval) };
}, [currentCount, qutesList, countUpAndDown])
currentCount 상태를 가지는 이유는 수직으로 움직일 명언들에게 translateY 속성을 이용해 (현재 카운터 값 * 요소 높이) 만큼 이동시키기 위함이다. 즉, 보여질 항목을 의미하는 상태이다. useEffect 안에서 1씩 올라가는 대신 특정한 시점(List의 최대 길이 도달)에 currentCount가 1로 초기화되는 동작을 할 수 있게끔 만들어준다. currentCount가 커짐에 따라 -만큼 이동하여 다음 명언이 나타날 것이다. 다음은 CSS를 작업해줘야 할 것 같다.
CSS 작업을 하던 도중 currentCount 값에 따라 translateY 속성을 변경시키려고 하니 li의 높이 값에 따라 해당 li의 높이만큼 Y을 변경시켜야 했다.
4. 이동 시키기
const QuotesAutoSlider = () => {
const [currentCount, setCurrentCount] = useState(0);
const [qutesList, setQutesList] = useState(quotesDummyData)
const slideUlRef = useRef();
const slideLiRef = useRef();
const countUpAndDown = useCallback(() => {
if (currentCount < qutesList.length - 1) {
setCurrentCount(currentCount + 1)
} else {
setCurrentCount(0);
}
}, [currentCount, qutesList]);
useEffect(() => {
let interval = setInterval(() => {
countUpAndDown();
}, 7000)
return () => { clearInterval(interval) };
}, [currentCount, qutesList, countUpAndDown])
useEffect(() => {
slideUlRef.current.style.transform = `translateY(-${slideLiRef.current.offsetHeight * currentCount}px)`;
}, [currentCount]);
return (
<div className="quotes__container">
<ul ref={slideUlRef}>
{
qutesList.map(qutes => (
<li className="quotes__item-wrapper" ref={slideLiRef} key={qutes.id}>
<p>{`" ${qutes.quote} "`}</p>
<span>{`- ${qutes.author} `}</span>
</li>
))
}
</ul>
</div>
)
}
slideLiRef를 추가하여 currentCount 값이 변경됨에 따라 ul태크의 Y값을 li태그의 offsetHeight * currentCount 크기만큼 이동시켰더니 문제없이 동작하였다. 이제 디자인을 다듬어 주기만 하면 될 것 같다.
이쁘지는 않다.. ㅋㅋ useEffect를 다룬 기억을 더듬으면 useEffect는 최대한 사용하지 않고 event로 처리할 수 있는 부분은 event로 처리해야 한다. Count 값에 따라 Y값을 변경시키는 useEffect을 event로 변경해볼 수 있을 것 같다.