React로 슬라이드 컴포넌트를 제작하던 도중 상태가 변경되면 CSS 애니메이션이 초기화되도록 구현할 필요가 있어서 관련 정보를 찾아봤다.
애니메이션을 가지는 요소에 animation 값을 "none"으로 부여했다가 null을 부여하는 방법이였다.
const resetAnimation = () => {
animationElement.current.style.animation = "none"; --- A
animationElement.current.style.animation = null; --- B
}
하지만 위 코드처럼 작성하게 되면 애니메이션 초기화가 되지 않는다.
브라우저는 페이지가 연속적으로 변경됨으로 인해서 발생하는 자원 낭비를 막기 위해서
변경사항을 누적해뒀다가 A
, B
코드가 각각 실행될 때마다 화면을 다시 그리지 않고 마지막에 일괄 처리하여 화면을 다시 그리게 된다.
이때 일괄처리하는 과정에서 초기 상태와 달라진게 없다면 브라우저는 해당 요소를 다시 그리지 않는다.
animationElement.current.style.animation = "none"
-> 브라우저는 해당 요소의 animation을 none으로 설정하지만 리렌더링을 하지는 않는다.animationElement.current.style.animation = null;
-> 브라우저는 해당 요소의 animation을 none으로 설정하지만 리렌더링을 하지는 않는다.- 해당 함수가 완료되었으므로 브라우저는 리렌더링을 하기 위해서 값을 확인하지만 결론적으로 변한 값이 없으므로 리렌더링을 발생시키지 않는다!
setTimeout을 이용해서 구현한 방법이다.
const animationElement = useRef(null);
const resetAnimation = () => {
animationElement.current.style.animation = "none";
setTimeout(()=>{
animationElement.current.style.animation = null;
},500);
}
setTimeout을 이용해서 "none"
설정하는 코드와 null
로 설정하는 코드에 시간차를 둬서 브라우저가 다시 그릴 시간을 주는 방법이 있다.
하지만 해당 경우는 내가 구현하고자 하는 컴포넌트랑 잘 맞지 않아서 다른 방법을 찾아보았다.
const resetAnimation = () => {
animationElement.current.style.animation = "none";
void animationElement.current.offsetWidth; --- 3
aniamtionElement.current.style.animation = null;
}
두 연산 사이에 void 요소.offsetWidth
를 한줄 추가하는 방법이다.
offsetWidth 값을 구하기 위해서 브라우저는 변경사항 일괄 처리를 포기하고 페이지를 다시 그려야만 하기 때문에 두 코드 사이에 강제적인 페이지 렌더링이 발생해서 정상적으로 애니메이션 초기화가 발생한다!
animationElement.current.style.animation = "none"
-> 브라우저는 해당 요소의 animation을 none으로 설정하지만 리렌더링을 하지는 않는다.void animationElement.current.offsetWidth;
-> offsetWidth의 값을 구하기 위해서 브라우저는 이전 변경사항들을 적용하고 리렌더링을 실시한다.animationElement.current.style.animation = null;
-> 브라우저는 해당 요소의 animation을 none으로 설정하지만 리렌더링을 하지는 않는다.- 함수가 완료되었으므로 브라우저는 변경사항을 반영하여 화면을 다시 그리게 된다.