Skip to content

React 컴포넌트에 애니메이션을 적용해보자 🏃🏻💨

n-ryu edited this page Dec 14, 2022 · 27 revisions

현재까지의 상황

다이어그램 뷰 구현 상황

  • 사용자가 추가한 Todo들의 선후관계를 플로우차트 형태로 보여주는 다이어그램 뷰를 구 현했다.
  • 다이어그램 뷰의 X축은 전체적인 우선순위 순으로 정렬되고, Y축은 Todo간 선후관계의 위계를 나타낸다. (선후관계가 있다면, 나중에 해야하는 Todo의 Y 위치가 더 크다)
  • 토글 버튼을 통해서 다이어그램에 이미 완료된 Todo도 함께 표시할지, 아직 하지 않은 Todo들만 표시할지 결정할 수 있다.
  • 앞으로 다이어그램 뷰 내에서도 Todo를 생성, 수정하고, 선후관계도 즉석에서 추가, 제거가 가능한 기능을 추가할 예정이다.

🤔하지만 뭔가 부족한걸...?

0 NoAnimation

  • 다이어그램 뷰에 표시되는 Todo의 목록이 바뀔 때 어떤 변화가 일어나는 것인지 알기가 어렵다.
  • 지금은 이미 완료된 Todo 표기를 바꿀 때만 이런 트랜지션이 있지만, 다이어그램 뷰 내에서 추가, 삭제, 편집이 가능하다면 어떤 변화가 일어난 것인지 사용자에게 보여주어야 사용자가 자신의 입력 제대로 반영된 것인지 판단하기 쉽다.
  • 다이어그램을 구성하는 Todo Block과 선후관계 vertex들이 다이어그램에 추가되고 삭제될 때 애니메이션 있으면 사용자가 이해하기도 쉽고 미려한 UX를 제공할 수 있을 것이다!

다이어그램에 애니메이션을 넣어보자

일단 CSS transition 옵션부터 넣어보자

1 TransitionOnly

  • TodoBlock 컴포넌트와 TodoVertex 컴포넌트의 스타일에 transition: transform 1s를 추가했다.
  • 기본적으로 리액트에서 Array.map을 통해 생성된 컴포넌트들은 key값을 통해서 동일 컴포넌트인지 판별이 되므로, 표시 데이터 변화 전과 후 모두에 존재하는 컴포넌트들은 그 위치가 자연스럽게 트랜지션 애니메이션이 적용되는 것을 확인할 수 있다.
  • 하지만 기존에 없었던 컴포넌트가 생기거나 있었던 컴포넌트가 없어지는 경우, 그냥 추적할 객체 자체가 없었거나 사라지므로 애니메이션 없이 갑자기 Todo Block이나 Vertex가 사라지는 것을 확인할 수 있다.

생성되고 삭제되는 컴포넌트를 어떻게 추적할 수 있을까?

  • 현재 데이터 저장 방식의 문제

    State Structure without Animation

    • 기존에는 TodoList API에서 받아온 데이터를 다이어그램을 그리기 위한 데이터로 변환하고, 그 데이터를 직접 <Diagram> 컴포넌트에 상태로 보관했다.
    • 그리고 상태로 저장된 데이터를 .map()으로 JSX 컴포넌트로 변환해서 여러 다이어그램 요소들을 그려주게 된다.
    • 하지만 이렇게 데이터를 바로 상태로 보관을 하면, 새로운 요소가 추가되거나 삭제되는 것을 <Diagram> 컴포넌트는 전혀 모르므로, 생성이나 제거 등의 변화를 추적할 수 없다!
  • 변화를 고려한 데이터 저장 방식

    State Structure considering Animation

    • 요소의 추가, 삭제를 추적하려면 데이터를 바로 상태로 보관하는 것이 아니라, 어떤 데이터가 새로 생겼고, 없어졌는지를 판별하고, 판별 결과와 정보들을 묶고 그 결과의 합집합을 통째로 상태로 저장해 두어야 한다.
    • 이렇게 저장을 한 뒤, 새로 생겨나는 요소들은 생성 트랜지션(애니메이션)을, 없어지는 요소들은 제거 트랜지션(애니메이션)을 적용시켜주면 생성, 제거 애니메이션을 구현할 수 있다.
    • 변경 이전과 이후 데이터의 합집합을 변화상태(생성, 삭제, 불변)와 함께 보관하면 요소들의 변화 추적이 가능하므로, 애니메이션을 넣을 수 있을 것이다!

실제로 요소 상태 추적 로직을 구현해보자

  • 일단 기존 상태와 새로운 상태를 받아서 요소들의 변화를 추적해보자.

      const mountData = [...IncomingData].filter(([key]) => !prev.has(key));
      const idleData = [...IncomingData].filter(([key]) => prev.has(key));
      const unmountData = [...CurrentData].filter(([key]) => !next.has(key));
    
    • HashMap 구조로 인자로 입력되는 신규 데이터와 기존 데이터를 비교해서 생성되는 요소들, 유지되는 요소들, 제거되는 요소들을 우선 분류해보았다.
  • 새로운 변화가 있어도 이전의 변화도 알고는 있어야 한다

    • 위의 데이터 관리 로직 그림에서는 새로운 변화 (기존 데이터와 신규 데이터의 차이)만을 저장하한다. 하지만 트랜지션이 1초가 걸린다고 한다면 그 사이에 변화가 두 번, 세 번, 심지어 만 번도 일어날 수 있다는 문제가 있다!
    
    

2 Animation

개선 또 개선!

  • Vertex가 생성 추가될 때, 연관된 Todo를 위치를 추적하도록 하자 3 MorePrecisePathAnimation 4 EditAnimation

  • 가끔씩 애니메이션이 스킵되는 문제가 있다? 5 EditAnimationWithBug 6 EditAnimationWithoutBug

💊 비타500

📌 프로젝트

🐾 개발 일지

🥑 그룹활동

🌴 멘토링
🥕 데일리 스크럼
🍒 데일리 개인 회고
🐥 주간 회고
👯 발표 자료

Clone this wiki locally