모 기업의 채용 과제에 사용했던 화면에 들어왔을 때 애니메이션 동작을 실행하도록 하는 기능을 포스팅하겠습니다
import React from 'react'
import styled from '@emotion/styled'
const ContentDiv = styled.div`
height: 200px;
font-size: 36px;
margin: 20px;
display: flex;
align-items: center;
justify-content: center;
animation-name: opacity;
animation-duration: 5000ms;
@keyframes opacity {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
`
const App = () => {
return <ContentDiv>글자 등장!</ContentDiv>
}
export default App
기본적인 애니메이션 코드입니다
새로고침하면 나타난것처럼 동작합니다
여러 사이트에서 스크롤을 내려서 화면에 잡혔을 때 슝~ 하고 움직이는 애니메이션을 본적이 있으신가요?
위 코드의 애니메이션을 화면에 잡혔을 때 동작하도록 바꾸겠습니다
사용자에게 많은 데이터를 보여주는 방법이라는 지난 글에서 IntersectionObserver를 다룬적이 있습니다
특정 DOM이 사용자가 보는 화면 (viewport)에 들어왔을 때 감지할 수 있습니다
useIntersectionObserver라는 훅을 만들어서 사용해보겠습니다
import { useEffect, useRef, useState } from 'react'
import type { RefObject } from 'react'
const useIntersectionObsever = (targetRef: RefObject<HTMLDivElement>) => {
const [isInViewport, setIsInViewport] = useState(false)
const observer = useRef<IntersectionObserver>()
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
dom에 접근하는 ref를 인자로 받아서, state를 반환하는 훅입니다
observer에 잡히면 (viewport에 들어왔으면) state를 true로 만듭니다
import React, { useRef } from 'react'
import styled from '@emotion/styled'
import useIntersectionObsever from './hooks/useIntersectionObsever'
const ContentDiv = styled.div`
height: 200px;
font-size: 36px;
margin: 20px;
display: flex;
align-items: center;
justify-content: center;
&.animation {
animation-name: opacity;
animation-duration: 5000ms;
@keyframes opacity {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
}
`
const App = () => {
const ref = useRef<HTMLDivElement>(null)
const isInViewport = useIntersectionObsever(ref)
return (
<>
<div style={{ height: '2000px' }} />
<ContentDiv ref={ref} className={isInViewport ? 'animation' : ''}>
글자 등장!
</ContentDiv>
</>
)
}
export default App
App.tsx는 useObserver 훅으로 반환받은 값이 true면 클래스를 추가합니다
해당 클래스가 있을 때 애니메이션이 동작하도록 style을 수정합니다
스크롤을 내리면 클래스가 수정되고, 애니메이션이 동작합니다