let currentIndex = 0;
useEffect(() => {
const slide = setInterval(() => {
document.getElementsByClassName("masthead-slide")[currentIndex].classList.remove("active");
currentIndex++;
if (currentIndex > 4) currentIndex = 0;
document.getElementsByClassName("masthead-slide")[currentIndex].classList.add("active");
}, 4500);
return () => {
clearInterval(slide);
};
}, [currentIndex]);
개발 공부를 시작하고 처음 공부하고 자동 슬라이드를 구현하기 위해 다음처럼 작성했다. currentIndex 변수에 대해 다음과 같은 경고를 볼 수 있다.
Assignments to the 'currentIdx' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect.
- React Hook useEffect 내부의 'currentIdx' 변수에 대한 할당은 각 렌더 후에 손실됩니다. 시간이 지남에 따라 값을 보존하려면 useRef Hook에 저장하고 변경 가능한 값을 '.current' 속성에 유지합니다. 그렇지 않으면 이 변수를 useEffect 내부로 직접 이동할 수 있습니다.
자동 슬라이드 기능을 구현하면서 setInterval()
를 사용하는데에 있어 문제점이 있다는 것을 인식하고 이를 useInterval
커스텀 훅을 사용해서 개선할 예정이다.
// hooks/useInterval.ts
import { useEffect, useRef } from "react";
type UseInterval = {
(callback: () => void, interval: number): void;
}
const useInterval: UseInterval = (callback, interval) => {
const savedCallback = useRef<(() => void) | null>(null);
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
const tick = () => {
if (savedCallback.current) {
savedCallback.current();
}
}
const id = setInterval(tick, interval);
return () => clearInterval(id);
}, [interval])
}
export default useInterval;
const savedCallback = useRef<(() => void) | null>(null);
useRef
훅을 사용하여 리렌더링을 방지한다.useRef
는 함수형 프로그래밍에서 사용하는 ref
로 초기화된 ref 객체인 { current: null }을 반환하며 반환된 객체는 컴포넌트의 전 생애주기 동안 유지되어 useRef
로 관리하는 값은 값이 변경되어도 컴포넌트가 리렌더링되지 않는다.useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect
가 실행되어 savedCallback
의 current 값이 새로운 callback 데이터로 업데이트된다고 보면 된다.useInterval
훅은 리렌더링될 때마다 실행되어 업데이트된 state값을 가질 수 있게 만들고, state값을 업데이트하는 함수를 useInterval
훅에 전달하여 내부에서 savedCallback.current
에 저장하여 새로 업데이트된 state 값을 callback 데이터로 업데이트된다.useEffect(() => {
const tick = () => {
if (savedCallback.current) {
savedCallback.current();
}
}
const id = setInterval(tick, interval);
return () => clearInterval(id);
}, [interval])
useInterval(() => {
slideRef.current.forEach((item) => item.classList.remove('active'));
slideRef.current[currentIdx].classList.add('active');
setCurrentIdx((prev) => (prev >= 4 ? 0 : prev + 1));
}, 4500);