ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React] Styled-Components를 이용한 애니메이션
    programing/Web 2021. 1. 30. 21:47

    발단

    이상형 월드컵을 구현하다가, 각 아이템을 선택했을 때 밋밋하게 사진이 바뀌는 것이 마음에 안들어서, 애니메이션 효과를 주려고 했다.

    권장하는 방법

    styled-components에서 특정 이벤트 시 애니메이션을 트리거 하는 방법은 안나와 있었다.

    다만, 구글링을 해보니 다들 상태 기반 애니메이션을 사용하는 듯 했다.

    const ItemContainer = styled.div<ItemContainerProps>`
      ...
      ${(props) => (props.isFadeOut ? fadeOutAnimation : null)};
    `;

    나의 구현

    상태 기반으로 애니메이션을 트리거하기 위해, useState로 상태를 추가했다.

    export function ShowWindow(props: ShowWindowProps) {
      const [isFadeOut, setIsFadeOut] = useState(false);
    
      const onClickItem = (itemIndex: number) => () => {
        setIsFadeOut(true);
        ...
      };
      const onAnimationEnd = (e) => {
        ...
      };
    
      return (
        <SelectionArea>
          <ItemContainer
            isFadeOut={isFadeOut}
            onClick={onClickItem(leftItemIndex)}
            onAnimationEnd={onAnimationEnd}
          >
            ...
          </ItemContainer>
    
          <ItemContainer
            isFadeOut={isFadeOut}
            onClick={onClickItem(rightItemIndex)}
            onAnimationEnd={onAnimationEnd}
          >
            ...
          </ItemContainer>
        </SelectionArea>
      );
    }

    onClickItem 함수에서 isFadeout 의 상태를 true 로 변경하는데, 이 때 상태 변경에 따라 리렌더링이 되어, 한번 깜빡인 뒤 애니메이션이 실행되었다.

    클릭 시 깜빡인 후 fade-out 애니메이션이 동작한다.

    원인

    원인은 정확하진 않지만, isFadeout 상태가 변경됨에 따라, 이 상태에 의존하는 ImageContainer 가 리렌더링된 게 원인이 아닐까 싶다.

    해결

    결국, 고전적인 방법인 클래스 네임 기반 애니메이션으로 방법을 바꾸었다. (겸사겸사 애니메이션 주체도 상위 컴포넌트로 바꿨다.)

    const SelectionArea = styled.div`
      ...
      &.fade-out {
        animation: ${fadeOutKeyframes} 0.5s 1 ease alternate;
      }
    `;
    export function ShowWindow(props: ShowWindowProps) {
      const [selectedIndex, setSelectedIndex] = useState(0);
      const selectionArea = useRef<HTMLInputElement>(null);
    
      const onClickItem = (itemIndex: number) => () => {
        setSelectedIndex(itemIndex);
        selectionArea.current?.classList.add('fade-out');
      };
      const onAnimationEnd = () => {
        selectionArea.current.classList.remove('fade-out');
        ...
      };
    
      return (
        <SelectionArea ref={selectionArea} onAnimationEnd={onAnimationEnd}>
          <ItemContainer
            onClick={onClickItem(leftItemIndex)}
          >
            ...
          </ItemContainer>
    
          <ItemContainer
            onClick={onClickItem(rightItemIndex)}
          >
            ...
          </ItemContainer>
        </SelectionArea>
      );
    }

    클릭해도 깜빡임이 없다.

    사실 이게 올바른 방법인지는 잘 모르겠다. 리서치 하기가 넘 귀찮스..

     

    'programing > Web' 카테고리의 다른 글

    [web] Intersection Observer API와 활용  (0) 2021.05.16
    [CSS] column-count를 이용하여 masonry layout 구현하기  (2) 2021.02.28
    [Web] Web Storage에 대하여  (2) 2020.12.26
    [Web] JSON Web Token  (0) 2020.12.03
    [WEB] CORS에 대한 정리  (0) 2020.07.22

    댓글

Designed by black7375.