본문 바로가기

자기계발

React Developer Tools를 활용한 React 애플리케이션 성능 최적화

React 애플리케이션에서 성능 최적화는 사용자 경험을 크게 향상시킬 수 있는 중요한 요소입니다. 특히, 이벤트가 빈번하게 발생할 때 불필요한 함수 호출을 줄이는 것은 매우 중요합니다. 이 글에서는 성능 최적화에 자주 사용되는 debounce와 throttle의 개념과 사용법, 그리고 이들의 차이점을 알아보겠습니다.

1. Debounce의 개념과 사용법

Debounce란?

Debounce는 사용자가 입력하거나 스크롤, 윈도우 리사이즈 등과 같은 이벤트가 연속적으로 발생할 때, 일정 시간 동안 이벤트가 발생하지 않을 때까지 함수 호출을 지연시키는 기술입니다. 이를 통해 불필요한 함수 호출을 방지하고, 성능을 최적화할 수 있습니다.

  • 주요 특징: 이벤트가 연속해서 발생할 때, 마지막 이벤트가 발생한 후 일정 시간 동안 이벤트가 더 발생하지 않으면 함수를 호출합니다.
  • 사용 예시: 검색창 입력, 윈도우 리사이즈 이벤트, 버튼 클릭 방지 등.
import React, { useState } from 'react';
import { debounce } from 'lodash';

function SearchInput() {
  const [query, setQuery] = useState('');

  // debounce를 사용하여 입력이 멈춘 후 500ms 후에 함수를 호출하도록 설정
  const handleInputChange = debounce((value) => {
    console.log('Search query:', value);
    setQuery(value);
  }, 500);

  return (
    <input
      type="text"
      placeholder="Search..."
      onChange={(e) => handleInputChange(e.target.value)}
    />
  );
}

export default SearchInput;

 

2. Throttle의 개념과 사용법

Throttle란?

Throttle는 연속적으로 발생하는 이벤트를 일정 시간 간격으로 제한하여 함수를 호출하는 기술입니다. 이벤트가 발생할 때마다 함수를 호출하지 않고, 지정된 시간 동안 함수가 한 번만 실행되도록 합니다.

  • 주요 특징: 이벤트가 연속해서 발생하더라도 일정한 간격으로 함수가 호출되도록 하여 성능을 최적화합니다.
  • 사용 예시: 스크롤 이벤트, 마우스 이동, 윈도우 리사이즈 등.
import React, { useEffect } from 'react';
import { throttle } from 'lodash';

function ScrollHandler() {
  // throttle을 사용하여 스크롤 이벤트를 300ms 간격으로 제한
  const handleScroll = throttle(() => {
    console.log('Scroll event triggered');
  }, 300);

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => {
      window.removeEventListener('scroll', handleScroll);
    };
  }, []);

  return <div style={{ height: '200vh' }}>Scroll down to see throttle effect</div>;
}

export default ScrollHandler;

 

3. Debounce와 Throttle의 차이점

  • 동작 방식:
    • Debounce: 마지막 이벤트 발생 후 일정 시간 동안 추가 이벤트가 발생하지 않으면 함수를 호출합니다.
    • Throttle: 이벤트가 연속해서 발생해도 일정한 간격으로만 함수를 호출합니다.
  • 사용 사례:
    • Debounce: 사용자가 입력을 마치고 나서 API 호출을 해야 할 때, 검색창에서 입력이 끝난 후 데이터를 요청할 때 주로 사용합니다.
    • Throttle: 스크롤, 마우스 이동, 리사이즈 이벤트 등 고빈도 이벤트를 제어할 때 사용합니다.
  • 주요 차이점:
    • Debounce는 마지막 이벤트 후 일정 시간 동안 기다려야 실행되기 때문에 연속 이벤트의 마지막에만 실행됩니다.
    • Throttle은 연속된 이벤트 중에서도 일정 간격으로 실행되기 때문에 고빈도 이벤트에 최적화되어 있습니다.

간단 비교 예시

  • Debounce: 사용자가 키를 입력할 때마다 마지막 입력 후 500ms 동안 대기 후 API 호출.
  • Throttle: 스크롤 이벤트가 발생할 때마다 300ms 간격으로만 이벤트를 처리.

마무리

Debounce와 Throttle은 고빈도 이벤트로 인한 성능 문제를 해결할 수 있는 강력한 도구입니다. React 애플리케이션에서 적절한 최적화 기법을 적용하여 사용자 경험을 향상시키고, 효율적인 코드 작성을 통해 성능을 높일 수 있습니다. 


 

과제 코드 : 

import React, { useState } from 'react';
import './App.css';

function App() {
  const [query, setQuery] = useState('');

  const handleChange = (event) => {
    setQuery(event.target.value);
    console.log('검색 쿼리:', event.target.value);
  };

  return (
    <div className="container">
      <h1>
        debounce와 throttle을
        <br />
        이용한 검색
      </h1>
      <div>
        <h2>Debounce</h2>
        <input
          type="text"
          placeholder="Debounce를 이용한 검색..."
          onChange={handleChange}
        />
      </div>
      <div>
        <h2>Throttle</h2>
        <input
          type="text"
          placeholder="Throttle을 이용한 검색..."
          onChange={handleChange}
        />
      </div>
    </div>
  );
}

export default App;
import React, { useEffect, useRef, useState } from 'react';
import './App.css';
/*
- **기본 요구 사항**:
    1. **디바운스와 스로틀 적용**:
        1. 주어진 기본 코드를 바탕으로 `lodash`의 `debounce`와 `throttle`을 사용하여 검색 기능을 구현합니다.
        2. 두 개의 입력 필드를 생성하고 각각 디바운스와 스로틀을 적용하여 검색 기능을 구현합니다.
        3. 디바운스와 스로틀을 적용한 검색 기능이 어떻게 작동하는지 이해할 수 있도록 콘솔에 로그를 찍어 결과를 확인합니다.
    2. **변경 사항 확인**:
        1. 디바운스와 스로틀이 적용된 입력 필드에 텍스트를 입력한 후, 브라우저의 콘솔을 확인하여 디바운스와 스로틀이 올바르게 적용되었는지 확인합니다.
        2. 콘솔 로그를 통해 두 기법의 차이점을 비교합니다.
*/
function App() {
  const [debounce, setDebounce] = useState('');
  const [throttle, setThrottle] = useState('');

  const debounceHandleChange = (event) => {
    setDebounce(event.target.value);
    console.log('Debounce 검색 쿼리:', event.target.value);
  };

  const throttleHandleChange = (event) => {
    setThrottle(event.target.value);
    console.log('Throttle 검색 쿼리:', event.target.value);
  };
  
  //debounce 셋팅
  useEffect(() => {
      const debounceTimer = setTimeout(() => {
        console.log('DebounceTimer!!!');
      }, 1000);
      return () => clearTimeout(debounceTimer);
    },[debounce]);

  //throttle 셋팅
  //throttle에 필요한 현재시간 설정 (Rerender에 독립적인 즉 컴포넌트 생명주기에 관계없는 useRef 함수 사용)  
  const time = useRef(new Date());
  useEffect(() => {
      const newTime = new Date(); //작업 들어올 때 시간 저장

      const throttleTimer = setTimeout(() => {
        console.log('ThrottleTimer!!!');
        time.current = new Date(); //작업 끝난 후 현재 시간 재조정
      }, 1000 - (newTime - time.current));
      return () => clearTimeout(throttleTimer);
    },[throttle]);

  return (
    <div className="container">
      <h1>
        debounce와 throttle을
        <br />
        이용한 검색
      </h1>
      <div>
        <h2>Debounce</h2>
        <input
          type="text"
          placeholder="Debounce를 이용한 검색..."
          onChange={debounceHandleChange}
        />
      </div>
      <div>
        <h2>Throttle</h2>
        <input
          type="text"
          placeholder="Throttle을 이용한 검색..."
          onChange={throttleHandleChange}
        />
      </div>
    </div>
  );
}

export default App;