프론트엔드에서 서비스가 성능이 좋은지 안좋은지는 대부분의 경우 사람이 체감할 수 있는 속도는 아니라고 생각합니다.
그럼에도 프론트엔드가 해결해야하는 성능 이슈들이 있습니다.
- 웹페이지의 번들 사이즈가 거대하여 로딩시간이 불필요하게 길 때
- 불필요한 랜더링으로 서비스에 악영향을 주고있을 때
오늘은 불필요한 랜더링을 개선한 이야기를 해볼까합니다.
물론 개발자는 props drilling이나, 비효율적인 상태처리, useEffect 무한랜더링등 코드적으로 문제가 되는 부분들을 선제적으로 파악하여 개선할 수 있습니다.
하지만 자신의 개선점들이 정말로 유용했는지를 파악하려면, 실질적인 데이터를 통해 유효성을 증명해야 합니다.
우선 React Profiler를 통해 문제를 확인해봅시다.
Profiler는 React 애플리케이션이 렌더링하는 빈도와 렌더링 “비용”을 측정합니다. Profiler의 목적은 메모이제이션 같은 성능 최적화 방법을 활용할 수 있는 애플리케이션의 느린 부분들을 식별해내는 것입니다. react 공식문서
리액트에서는 Profiler 를 통해 랜더링에 대한 성능을 측정할 수 있습니다.
현재 제가 진행중인 프로젝트에서 캔버스 API를 활용한 그림판 기능이 있습니다.
마우스 이동에 따라 이벤트가 발생하여 캔버스를 새로 그리고 있는데, 이 과정에서 약간의 버벅임 문제가 있었습니다.
Profiler로 녹화를 하며 마우스 이벤트를 직접 발생시켜, 그림판 사용에 따른 랜더링 동작을 분석해보았습니다.
주황색에 가까울 수록 랜더링이 오래걸린 노드이고, 파랑색일수록 짧은 노드입니다.
역시 전체 페이지가 리렌더링 되고 있었군요...ㅜ
그래프의 각 막대는 랜더링한 대상을 의미하며 트리구조의 랜더링을 표현하고 있습니다.
우리 프로젝트에서 필요한 랜더링은 빨간색 영역인 그림판 컴포넌트 뿐이지만, 상태 및 랜더링 관리의 실패로 루트 페이지의 모든 요소가 랜더링되고있었습니다.
그림판 컴포넌트의 랜더링에는 1ms가 필요하지만, 전체 페이지를 랜더링하며 7.1ms로 86%의 시간을 불필요한 랜더링에 사용하고 있었습니다.
생각보다 불필요한 랜더링에 걸리는 시간이 길군요.
그림판 기능의 특성 상 마우스이벤트를 자주 발생시킬것이며, 이대로 간다면 사용자가 느낄 수도 있는만큼 서비스에 악영향을 미칠 수도 있을 것 같습니다.
리액트는 state와 props를 통해 컴포넌트의 랜더링여부를 결정합니다.
우리 프로젝트가 모든 페이지를 랜더링하게 된 이유기도 하겠지요.
그림판 서비스는 하나의 모듈에서 상태와 데이터를 전부 관리하고 있었습니다.
페이지 내부에 그림판의 상태가 변하며, 모듈 전체의 랜더링을 발생시킨 것이죠.
모듈을 분리하고 ContextAPI를 통해 그림판에 필요한 상태와 동작들을 provider를 통해 전달하였습니다.
회색, 빗금은 이벤트에 따라 랜더링이 발생하지 않은 노드입니다.
제가 찾던 최적화 여기있네요!
리팩토링을 진행하며 트리구조는 약간 변경되었지만, ContextAPI를 적용한 후 실제 랜더링이 필요한영역(provider 및 그림판)만 랜더링이 된다는것을 확인할 수 있었습니다.
또한 시간도 1.1ms로 굉장히 많은부분이 해소가 되었군요!
단일 랜더링의 성능은 개선되었지만 서비스의 특성 상 잦은 그림판 편집 동작이 발생할 것이고 이는 단일 랜더링과는 거리가 있겠죠?
또한 리액트의 랜더링만으로는 실질적인 사용자 경험과 차이가 있을 수 있습니다.
사용자 경험을 수치적으로 측정하기 위해 Chrome 도구를 통해 Performance 측정을 사용하였습니다.
우선 사용자 동작을 다음과 같이 정의하였습니다.
사용자는 마우스 드래그를 통해 1초에 20번의 그림판 편집기능을 사용한다.
자동으로 그림판에 마우스 이벤트를 발생할 함수를 스크립트로 작성하고, 개선 전과 개선 후의 프로젝트에서 각각 실행해보았습니다.
![]() | ![]() |
---|
![]() | ![]() |
---|
확실히 cpu 사용량과 스크립트 실행에 사용되는 시간이 유의미하게 줄어든 것을 볼 수 있었습니다.
스크립트 실행시간은 76%감소하였군요!
평소엔 랜더링에대해 신경을 쓰는 편이라고 생각했습니다.
리액트를 사용하는 프론트엔드 개발자로서, state와 props관리를 통해 랜더링을 관리하는 역활은 필수적이니까요.
하지만 랜더링문제는 요즘 컴퓨터의 성능으로는 체감하기 어려운 주제라고 생각합니다.
저도 매번 context 또는 memo,callback 사용을 통한 랜더링 최적화 이후에 서비스 실사용에 큰 차이를 느끼지 못했거든요.
그래서 성능 측정도구들을 통해 제가 개선했던 그림판의 성능을 분석해보았습니다.
수치적으로 문제점을 파악하고, 개선결과를 분석한 경험은 제가 더욱 성장했다는 자신감을 느끼게 해주었습니다.