반응형
화면에 나타났을 때 어떤 애니메이션을 줄 것인가?
css &.on에 등록해두고 나중에 classNames 라이브러리를 이용해서 호출한다
const YearHistroy = styled.div`
display: flex;
flex-direction: column;
&.on {
animation-name: opacity;
animation-duration: 1000ms;
@keyframes opacity {
from {
opacity: 0;
transform: translateY(26px);
}
to {
opacity: 1;
transform: translateY(0px);
}
}
}
`;
화면에 나타났을 때 style을 추가하는 script 부분 ( + 강제 Re-Render)
리액트의 DOM은 과거 DOM과 비교해서 차이점만 확인해서 새로 그리는 경향이 있기 때문에
클릭할 때마다 새로 DOM에 등장한 것처럼 가장해서, 미리 설정한 애니메이션 효과를 주고 싶을 때는
해당 DOM을 강제로 rerender해야한다.
이 때 counter라는 state를 만든 다음에
클릭할 때마다 counter가 하나씩 커지고
해당 counter를 key값으로 받아서 부모 컴포넌트에 key로 설정해줄 수 있다
const [counter, setCounter] = useState<number>(0);
const ref = useRef<HTMLDivElement>(null);
const isInViewport = useIntersectionObsever(ref, counter);
const onClick = (index:number) => {
setCounter(counter => counter+1); // 강제 re-render를 위해서
}
return (
<Container>
<Years>
{
years.map((year:string, index:number) => {
return (
<Year
key={index}
data-year={year}
onClick={() => {onClick(index)}}
className={classNames({"clicked" : index === selectedIdx})}
>
</Year>
)
})
}
</Years>
<YearsHistory key={counter}>
<YearHistroy key={index} ref={ref} className={classNames({"on": isInViewport})}>
<Component../>
</YearHistroy>
</YearsHistory>
</Container>
특정 DOM이 화면(viewport)에 나타났을 때 감지하는 hook은 다른 어느 블로그를 보고 그대로 가져왔다.
그 분이 누구신지는 모르겠지만 여하튼 압도적 감사
나는 해당 hook에다가 re-render 되었을 때도 viewport에 처음 나타난 것처럼 착각하는 기능을 추가했다
위에서 설정한 counter가 바뀔 때마다 true 값을 반환하도록 설정해주었다
import { useEffect, useRef, useState } from 'react'
import type { RefObject } from 'react'
// 특정 DOM이 사용자가 보는 화면 (viewport)에 들어왔을 때 감지할 수 있습니다
const useIntersectionObsever = (targetRef: RefObject<HTMLDivElement>, counter: number) => {
const [isInViewport, setIsInViewport] = useState(false)
const observer = useRef<IntersectionObserver>()
useEffect(() => {
if (counter > 0) setIsInViewport(true);
}, [counter])
useEffect(() => {
if (!observer.current) {
const observerCallback = (entries: IntersectionObserverEntry[]) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setIsInViewport(true)
}
})
}
observer.current = new window.IntersectionObserver(observerCallback, {
threshold: 0
})
}
if (targetRef.current) {
observer.current.observe(targetRef.current)
}
return () => {
if (observer.current) {
observer.current.disconnect()
}
}
}, [targetRef])
return isInViewport
}
export default useIntersectionObsever
반응형
'프론트엔드 웹 > Next' 카테고리의 다른 글
Next.js에서 Swiper.js 사용해서 FullPage 효과 내기 (0) | 2023.06.19 |
---|---|
[Next] Victory Chart를 png 파일로 만들어서 Return 하는 Next.js API 만들기 (0) | 2023.05.24 |
Next.js API Router로 Chart.js 이미지 리턴하기 (0) | 2023.05.16 |
[Next] Next.13에서 API Route 사용하기 (0) | 2023.05.08 |
외부 URL에 새창으로 이동하기 (useRouter, window.location, window.open) (0) | 2022.06.28 |