React) Button 효과주기 (animation)

이해원·2022년 1월 15일
0

시작하기

목록 보기
25/27

Nice side effect : bump animation :)

(exercise of useEffect which needs for handling side effects)

버튼 수량정보가 들어있는데 거기에 뭔가 추가가되거나(빠지거나) 하는 state변화가 생기면 버튼이 커졌다작아지는 bump 애니메이션을 주고싶었다.

css :

.bump {
  animation: bump 300ms ease-out;
}

@keyframes bump {
  0% {
    transform: scale(1);
  }
  10% {
    transform: scale(0.9);
  }
  30% {
    transform: scale(1.1);
  }
  50% {
    transform: scale(1.15);
  }
  100% {
    transform: scale(1);
  }
}

const btnClasses = `${classes.button} ${classes.bump}`; 

일단 원래 있던 class에 bump 효과를 추가해주기위해 btnClasses라는 변수를 만들었다. 이렇게되면 페이지에 들어갔을시(첫렌더링시) 무조건 한번 bump애니메이션이 나타난다.

그런데 내가 원하는것은

1. state변화가 생길때마다 bump effect를 주고싶기때문에 useEffect 사용 + bump animation class가 조건부 실행될(추가될)때마다 이 컴포넌트를 재평가하고 리렌더링 해야하기때문에 useState 훅을 사용

const [ btnHighlighted , setBtnIsHighlighted] = useState(false);

useEffect 에서 effect function 에서는 if문은 장바구니안 물건이 0일때는 bump animation 없이 그냥 return 으로 끝나게 하고 그외의 경우(장바구니 물건 1개이상)에는 bump animation 준다.추가될때마다 bump effect가 적용되게 timer를 줘서 bump class를 줬다가 다시 없앰.

useEffect (() => {
if (items.length === 0 ) {
return;
}
setBtnIsHighlighted(true);
       const timer = setTimeout(() => {
           setBtnIsHighlighted(false);
       }, 300);
} ,[])

2. useState 에서 initialState 는 false로 주고 useEffect에서 function을 true로 실행시켜준다.

다음은 btnClasses 에 조건을 주는것인데 내가원하는것은 Highlighted 됬을때만 bump effect가 있었으면 좋겠어서

const btnClasses = `${classes.button} ${btnHighlighted ? classes.bump : ''}`;

이렇게 조건을 주었다.

4. useEffect dependency array 주기

useEffect에서 dependency array에 무엇이 바뀌었을때 리렌더링 될것이냐를 정해줘야 하는데 여기서는 나는 items 라는 특정한 것만 바뀌는것을 감지하고 싶어서 object destrucuring을해서 cartCtx에 있는 items를 꺼내서 ( const { items } = cartCtx; ) 가져와서 dependancy array에 넣어줌으로써 전체 context가 변할때가 아닌 items array가 변할때만 리렌더링 되게 하였다


//HeaderCartButton.js

const HeaderCartButton = (props) => {
    const [ btnHighlighted , setBtnIsHighlighted] = useState(false);
    const cartCtx = useContext(CartContext);
    const { items } = cartCtx;

    //reduce : a method which allows to transform an array of data into a single value
    const numberOfCartItems = items.reduce((curNum,item) => {
        return curNum + item.amount
    }, 0 );

    const btnClasses = `${classes.button} ${btnHighlighted ? classes.bump : ''}`;

    useEffect(()=>{
        if (items.length === 0){
            return;
        }
        setBtnIsHighlighted(true);
        const timer = setTimeout(() => {
            setBtnIsHighlighted(false);
        }, 300);

        //component가 사라졌을시 timer도 지워주는 clean up function
        return ()=>{
            clearTimeout(timer);
        };
    },[items]);

  return (
      <button className={btnClasses} onClick={props.onClick}>
        <span className={classes.icon}>
          <CartIcon />
        </span>
        <span>장바구니</span>
        <span className={classes.badge}>{numberOfCartItems}</span>
      </button>
  );
};

useEffect 에서 return ()=>{} 함수는 clean up function으로 리액트가 자동으로 부르는데 여기서 나는 clearTimeout 으로 timer를 없애서 bump effect가 재실행될때 타이머를 없애도록 하였다.

이 clean up function은 필수인데 그 이유는 timer 가 시간이 만료되기전에 다시 세팅될수도있기 때문이다. 예를들어 우리가 여러개의 아이템을 빠르게 오가며 추가한다면, 우리는 추가할때마다 옛날 타이머는 없애고 새 타이머가 작동했다고 확실히 하고싶을것이기 때문에 clean up function을 꼭 써주도록 하자!

profile
미어캣입니당

0개의 댓글