리액트, 리렌더링 시 CSS도 함께 리로드하는 방법(feat.animation)

컴포넌트 리렌더링 시 CSS도 함께 리렌더링하도록 만들기

리액트는 내부 로직에 따라 불필요한 렌더링을 최소화하도록 되어있지만 때로는 이 로직이 의도하지 않는 방식으로 작동할 때가 있습니다.

특히 애니메이션 효과를 줄 때 한 번만 실행되고 마는 것이 아니라 클릭 시마다 애니메이션이 동작하도록 만들고자 할 때 다음 방법을 유용하게 사용할 수 있습니다.

원리는 간단합니다.

리액트 컴포넌트는 state가 변경될 때마다 리렌더링을 실행하므로 클릭 시마다 state 값에 변경을 주면 됩니다.

예를 들어 다음 컴포넌트의 이미지를 확인해 보겠습니다.

const ColorChange = ({ color }) => {
  const DisplayBox = styled.div`
    width: 300px;
    height: 300px;
    display: flex;
    background: ${color};
    animation: change 3s;

    @keyframes change {
      0% {
        transition-timing-function: cubic-bezier(1, 0, 0.2, 0.5);
      }
      0% {
        width: 0;
      }
    }
  `;

  return <DisplayBox></DisplayBox>;
};

export default ColorChange;

---------------------------------------------------------------
컴포넌트 호출
<ColorChange color={color} /> 

red, green을 번갈아가며 누르면 컴포넌트에 전달되는 state가 변경되므로 컴포넌트가 리렌더링되면서 애니메이션이 동작합니다.

하지만 red인 상태에서 다시 red를 한번 더 누르면 애니메이션은 동작하지 않습니다.

그럼 클릭마다 CSS가 리렌더링되어 애니메이션이 작동하도록 하려면 어떻게 해야 할까요?

단순하게 클릭마다 전달되는 state의 값이 변경되도록 해주면 됩니다.

예를 들어 다음과 같이 컴포넌트 key 속성으로 임의의 값을 생성하여 전달합니다.

const [randomData, setRandomData] = useState(Math.random());

//버튼 클릭 시 호출 함수
const changeColor = () => {
     // 색상 변경 작업
     .......
     // 임의의 값 생성
     setRandomData(Math.random());
}

<ColorChange color={color} key={randomData} /> 

전달되는 color 값의 변경을 감지하여 리렌더링이 발생하고 그에 따라 CSS animation도 리로드되지만 계속 같은 버튼을 누르면 동일한 color 값이 전달되기 때문에 변경을 감지하지 못해 리렌더링이 되지 않는 원리입니다.

따라서 클릭 시 color 값은 변경되지 않더라도 key 값을 계속 변경하면 리액트는 컴포넌트 변경을 인식하여 계속 컴포넌트와 CSS를 리렌더링하게 됩니다.


렌더링은 최대한 리액트에게 맡기고 불필요한 렌더링은 최소화하되 위와 같이 필요한 부분에만 부분적으로 적용하도록 해야 합니다. 이를 위해서는 작동 방식의 이해가 필요합니다.