아래는 코드스테이츠 데모데이에서 기술 발표한 내용입니다.

처음 해본 리액트 프로젝트여서 리액트를 거의 모른 채 시작했음. 그러다보니 리액트 초보 개발자로서 겪은 다양한 이슈들이 있었음. 그 중 특별히 여러분과 나누고 싶은 경험은 리액트로 좀 더 쾌적한 게임을 만들기 위해 노력했던 점.

TL;DR

DOM painting 소요 시간이 81% 감소

정적 웹사이트

우리가 접하는 보통의 정적 웹사이트의 경우 유저 인터랙션과 그에 수반되는 컴포넌트 렌더링이 밀리세컨드 단위로 일어나지는 않음. 우리가 흔히 보는 네이버 뉴스를 생각해보면 기사 제목을 클릭하면 기사 내용이 보이고 화면을 아래로 스크롤 하면 댓글 목록이 lazy load되는 정도가 대부분

동적 웹사이트

조금 더 다이나믹한 구글 캘린더의 경우에도 유저 인터랙션과 별개로 진행되는 이벤트는 없고 유저의 인터랙션이 있어야 순차적으로 해당 컴포넌트가 렌더됨.

게임은 밀리세컨드 단위의 상호작용이다

이런 웹사이트들과 달리 블록팡은 게임이기 때문에 타이머, 스테이지 정보, 획득 포인트, 블록 생성, 파괴, 유저의 키 인풋 등 중요 이벤트가 밀리세컨드 단위로 일어남. 또한 유저의 인터랙션과 상관없이 타이머 컴포넌트는 계속해서 상태가 업데이트 되고 렌더링됨

블록팡이 점점 느려지기 시작했다 게임보드 안에서 여러개의 컴포넌트가 동시다발적으로 상태를 업데이트하고 그에 따라 다시 렌더링이 되다보니 블록이 몇개만 쌓여도 퍼포먼스에 문제가 생기기 시작했음.

Performance Fail === Project Fail

쾌적한 게임 렌더링은 프론트엔드 담당 엔지니어들의 가장 큰 과제였음

어떻게 하면 좀 더 쾌적한 리액트 게임? 게임 프로토타입이 어느 정도 완성되자 최적화 작업을 시작했음

느린 이유

기존의 거대한 게임 파일은 단 하나의 컴포넌트에서 여러개의 DOM element를 렌더링했음. 타이머의 경우 10밀리세컨드 단위로 상태가 업데이트 되는데, 이 말은 게임 파일이 렌더하는 DOM tree의 전체 구조를 리액트가 10밀리세컨드마다 비교해야 한다는 것임.

그게 왜 문제일까

DOM tree를 비교(diffing)하는데 뛰어난 알고리즘을 가지고 있는 리액트의 강점을 살릴 수 없다 그럼 DOM tree는 어떻게 만들어질까

브라우저의 DOM Painting (1)

브라우저는 문자열로 이루어진 HTML 마크업을 파싱해서 DOM 트리를 만듦 그 다음 CSS 마크업을 파싱해서 CSSOM 트리를 만들고 이 두 개의 트리를 하나의 트리로 합쳐서 개별 노드를 화면에 그려줌

Tree 구조에서 기존의 tree를 새로운 tree로 변경하는데에는 일반적으로 O(n^3)의 time complexity를 가진다고 알려져 있음 이 말은 HTML문서에 100개의 DOM Element를 가진 Tree의 경우 DOM 페인팅이 일어나기까지 최대 백만번의 비교가 필요할 수 있다는 뜻

리액트가 이걸 참 잘해요

리액트는 O(n)의 time complexity를 가진 효율적인 diffing algorithm이 강점 리액트는 state나 props의 변화를 감지하고 그에 해당하는 Virtual DOM tree의 변동 전후를 비교해서(diffing) 변동된 부분만 다시 렌더함 (reconciliation)

분할된 컴포넌트

단 하나의 게임 파일이 모든 컴포넌트를 담고 있고 렌더하는 구조에서 철저히 컴포넌트별 파일 구조로 변경했음 이런 구조에서는 게임 파일에서 관장하는 Timer, Stage, Score, 블록의 상태 변화가 게임 보드와 블록 컴포넌트에 영향을 끼치지 않기 때문에 board와 block이 매번 diffing 되지도 않고 매번 렌더되지도 않음 그만큼 시간이 절약되므로 퍼포먼스도 좋아지는 원리

Painting 소요 시간 대폭 감소

마지막

리액트 프로젝트 그것도 게임을 만드는 건 처음이어서 각종 시행착오가 있었지만 아주 즐거운 경험이었다. 우리 모두 짱짱 개발자가 됩시다.