useSlideFilterOption 훅
import { AnimationControls, useAnimation } from "framer-motion";
import { MutableRefObject, useEffect, useRef, useState } from "react";
interface IReturn {
homeContentsRef: MutableRefObject<HTMLDivElement | null>;
controls: AnimationControls;
}
function useSlideFilterOption(): IReturn {
const [scrollY, setScrollY] = useState<number>(0); // 현재 스크롤 위치
const [lastScrollY, setLastScrollY] = useState<number>(0); // 마지막 스크롤 위치
const homeContentsRef = useRef<HTMLDivElement | null>(null); // 스크롤 영역 컨텐츠
const [scrollDirection, setScrollDirection] = useState<"up" | "down" | null>(
null
); // 스크롤 방향을 저장하기 위한 상태 변수
// Framer Motion 애니메이션 컨트롤러
const controls = useAnimation();
// 스크롤 이벤트를 처리하기 위한 useEffect
useEffect(() => {
const handleScroll = () => {
if (homeContentsRef.current) {
const homeContentsScrollY = homeContentsRef.current.scrollTop;
setScrollY(homeContentsScrollY);
// 스크롤 방향 판단 로직
if (scrollY > lastScrollY && scrollY >= 60) {
setScrollDirection("down");
} else if (scrollY < lastScrollY && scrollY >= 60) {
setScrollDirection("up");
} else {
setScrollDirection(null);
}
setLastScrollY(scrollY);
}
};
const element = homeContentsRef.current;
element?.addEventListener("scroll", handleScroll);
// 컴포넌트 언마운트 시 이벤트 리스너 제거
return () => {
element?.removeEventListener("scroll", handleScroll);
};
}, [scrollY, lastScrollY]); // 의존성 배열에 scrollY, lastScrollY 포함
// 스크롤 방향에 따라 애니메이션 실행
useEffect(() => {
if (scrollDirection === "up") {
controls.start({
y: 0,
opacity: 1,
transition: { type: "tween", duration: 0.3 },
});
} else if (scrollDirection === "down") {
controls.start({
y: -60,
opacity: 0,
transition: { type: "tween", duration: 0.3 },
});
}
}, [scrollDirection, controls]); // 의존성 배열에 scrollDirection, controls 포함
return { homeContentsRef, controls };
}
export default useSlideFilterOption;
HomeMain 컴포넌트
function HomeMain(): JSX.Element {
const { homeContentsRef, controls } = useSlideFilterOption();
return (
<main className={styles.container}>
<section ref={homeContentsRef} className={styles.homeContents}>
<motion.section
animate={controls}
className={styles.filterOptionContainer}
>
<p className={styles.filterOption}>필터링 옵션</p>
</motion.section>
{[...Array(12)].map((_, i) => (
<HomeContent key={i} />
))}
</section>
</main>
);
}
위 방법은 불필요한 리렌더링을 너무 많이 발생시켜서 코드를 조금 수정 했습니다.