폭죽을 터트려보자 (최적화를 곁들여서)

adultlee·2023년 11월 27일
42

NDD

목록 보기
10/16
post-thumbnail

저희는 지금 무료 면접 서비스인 곰터뷰를 개발 중입니다.

개발 도중 Interview를 진행하는 페이지에서 유저의 마지막 면접이 종료가 되었을때,
유저에게 축하(?)의 의미를 담은 이벤트를 제공하기 위해서 도입되었습니다!

+) 결과물

React-Confetti 사용

어떤 라이브러리를 사용해볼까 하다가 react-confetti를 발견하게 되었습니다.

React-Confetti NPM

해당 라이브러리는 굉장히 가볍고 무엇보다 사용하는 방법 자체가 어렵지 않았습니다.

import React from 'react'
import Confetti from 'react-confetti'

export default () => {
  return (
    <Confetti />
  )
}

그저 react 프로젝트 내부에서 사용해주기만 하면 되는 어렵지 않은 기능이었습니다!
하지만 소소한 문제가 발생했었는데!

바로 잘 되는데 문제가 발생!

Interview 페이지 렌더링이 끝난이후 해당 Confetti를 호출한다음 화면의 크기를 변동하게 된다면 다음과 같은 이슈가 발생하게 됩니다.

해당 이슈는 canvas기반의 confetti가 선언과 동시에 현재 view 사이즈를 바탕으로 컴포넌트 크기를 결정하기 때문에 이후 view의 사이즈가 변화가 생겼을 시 반영하지 못하는 문제가 발생합니다.

따라서 window resize가 됨에 따라 다시 confetti의 크기를 변동해야할 필요가 있었습니다.

그래서 간단히 useEffect를 기반으로 window resize이벤트를 통해서 다시 confetti를 렌더링해 주었습니다. 그랬더니 다음과 같은 이슈가 발생했습니다.

무수히 많은 렌더링... 당연하다...!

당연하게도 window.resize 이벤트를 통해서 리렌더링을 시켜주는경우 window size의 변화가 조금이라도 생긴다면 다음과 같이 매 순간마다 리렌더링을 진행하기 때문에 렌더링 성능에 큰 저하가 생기게 됩니다. 저는 그래서 이를 Debounce로 해결했습니다.

렌더링 최적화 (by Debounce)

디바운스(debounce)는 프로그래밍에서 사용되는 기술로, 특히 사용자 인터페이스와 관련된 이벤트 처리에 자주 사용됩니다. 디바운스는 연속적으로 발생하는 이벤트들 중에서 단 하나의 이벤트만을 처리하여, 불필요한 함수 호출의 횟수를 줄이는 데 목적이 있습니다. 이는 성능 최적화와 사용자 경험 향상에 중요한 역할을 수행합니다!

디바운스의 동작 원리
디바운스의 기본 원리는 "일정 시간 동안 추가적인 이벤트가 발생하지 않으면, 마지막에 발생한 이벤트를 처리한다"입니다. 예를 들어, 사용자가 입력 필드에 글을 타이핑하는 경우를 생각해볼 수 있습니다. 사용자가 타이핑을 멈출 때까지 기다렸다가, 일정 시간(예: 300ms)이 지난 후에만 입력값에 대한 처리(예: 검색, 유효성 검사)를 수행합니다.

구현된 코드

import { useState, useEffect } from 'react';

const useWindowSize = () => {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    let timeoutId: number;

    const handleResize = () => {
      window.clearTimeout(timeoutId); // 매번 이벤트를 제거 합니다. 즉 resize event가 등록될때 마다 이전의 이벤트를 제거합니다. 
      timeoutId = window.setTimeout(() => { 
        setWindowSize({
          width: window.innerWidth,
          height: window.innerHeight,
        });
      }, 250); 
    };

    window.addEventListener('resize', handleResize); // 이벤트 추가 

    return () => {
      window.removeEventListener('resize', handleResize); // 해당 컴포넌트가 unmount 될때 제거 됩니다. 
      window.clearTimeout(timeoutId);
    };
  }, []);

  return windowSize;
};

export default useWindowSize;

해당 코드를 통해서 windowSize를 받아, confetti 컴포넌트에 인자로 넣어주면 다음과 같은 결과물을 확인할 수 있습니다.

Debounce가 적용된 최종 결과

조심스럽게 떨어지는 색종이가 이쁘군요!

2개의 댓글

comment-user-thumbnail
2023년 12월 4일

안녕하세요!
저도 Confetti 라이브러리에 관심을 갖고 있었지만 canvas의 resize 이벤트 대응에 대한 점을 생각치 못했어서 벨로그 트렌드에서 adultlee님의 글을 흥미롭게 읽게 되었어요. 다만 몇가지 프로젝트를 공부하는 입장에서 궁금한 점이 있는데 질문 드려도 괜찮으실까요 ?

  1. 진행중이신 프로젝트가 면접 서비스이다 보니 면접을 완료한 이후에 유저가 resize event를 일으킬 만한 '유저 플로우'가 있을지 궁금합니다.
  2. 그런 유저플로우가 발생할 가능성을 고려해서 개발 task를 나누시는지도 궁금합니다.
  3. 이런 최적화 작업은 기능 개발 이후에 테스트 과정에 이루어지는지, 기능 개발과 동시에 작업하시고 다음 task로 넘어가시는지 궁금합니다.

전체적으로 개발 프로세스에서 task를 관리하는 법에 대해 질문드리고 싶었는데 이야기 나눠주시면 감사하겠습니다!
프로젝트 화이팅입니다~~!

1개의 답글