React를 사용하다 보면 사용자 입력 이벤트나 스크롤 이벤트처럼 고빈도로 발생하는 작업을 최적화해야 할 때가 많습니다. 이때 debounce와 throttle은 성능 최적화를 위해 자주 사용하는 기법입니다. 이번 글에서는 debounce와 throttle의 차이점, React에서의 사용법, 그리고 실제 사례를 통해 어떻게 적용할 수 있는지 알아보겠습니다.
1. debounce와 throttle이란?
debounce
Debounce는 특정 이벤트가 연속적으로 발생할 때, 마지막 이벤트가 발생한 이후 일정 시간이 지난 뒤에 단 한 번 실행되도록 만드는 기법입니다. 주로 사용자가 입력 필드를 빠르게 타이핑하거나 검색 요청과 같이 불필요한 중복 작업을 방지해야 할 때 유용합니다.
동작 원리
- 이벤트가 발생할 때마다 타이머를 초기화합니다.
- 일정 시간이 지나도 추가 이벤트가 발생하지 않으면 콜백 함수를 실행합니다.
사용 예시
- 검색어 입력 필드에서 사용자가 입력을 멈춘 후 요청 보내기.
- 창 크기 변경 이벤트 처리.
throttle
Throttle은 특정 이벤트가 연속적으로 발생하더라도, 정해진 시간 간격으로 한 번씩만 실행되도록 만드는 기법입니다. 주로 스크롤 이벤트나 마우스 이동 이벤트처럼 짧은 간격으로 발생하는 작업에서 사용됩니다.
동작 원리
- 이벤트가 발생하면 지정된 시간 동안 추가 이벤트를 무시합니다.
- 지정된 시간이 지나면 다시 이벤트를 처리할 수 있습니다.
사용 예시
- 스크롤 위치에 따라 콘텐츠를 로드할 때.
- 마우스 드래그 이벤트 처리.
2. React에서 debounce와 throttle 사용하기
React에서 debounce와 throttle을 구현하려면 lodash 또는 lodash-es 라이브러리의 debounce와 throttle 함수를 사용하는 것이 일반적입니다. 아래는 각각의 구현 방법입니다.
2.1 debounce 사용하기
설치
먼저 lodash를 설치합니다:
npm install lodash
기본 구현
검색 입력 필드에서 debounce를 적용하는 예제입니다:
import React, { useState, useCallback } from "react";
import _ from "lodash";
function SearchInput() {
const [query, setQuery] = useState("");
// debounce로 최적화된 함수 생성
const handleSearch = useCallback(
_.debounce((searchText) => {
console.log("API 요청: ", searchText);
// 여기에 API 요청 코드를 작성합니다.
}, 500), // 500ms 대기
[]
);
const handleChange = (e) => {
const { value } = e.target;
setQuery(value);
handleSearch(value); // debounce된 함수 호출
};
return (
<div>
<input
type="text"
value={query}
onChange={handleChange}
placeholder="검색어를 입력하세요"
/>
</div>
);
}
export default SearchInput;
주요 포인트
- _.debounce를 사용하여 검색 요청을 제한합니다.
- useCallback으로 메모이제이션하여 컴포넌트가 리렌더링될 때마다 debounce 함수가 재생성되지 않도록 합니다.
2.2 throttle 사용하기
기본 구현
스크롤 이벤트에 throttle을 적용하는 예제입니다:
import React, { useEffect } from "react";
import _ from "lodash";
function ScrollTracker() {
useEffect(() => {
// throttle로 최적화된 함수 생성
const handleScroll = _.throttle(() => {
console.log("스크롤 위치: ", window.scrollY);
}, 200); // 200ms 간격
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
return <div style={{ height: "200vh" }}>스크롤 이벤트를 확인하세요!</div>;
}
export default ScrollTracker;
주요 포인트
- _.throttle를 사용하여 스크롤 이벤트의 과도한 호출을 방지합니다.
- useEffect에서 이벤트 리스너를 등록하고 컴포넌트가 언마운트될 때 클린업합니다.
3. 실무에서의 활용 사례
3.1 입력 필드에서 실시간 유효성 검사
사용자가 이메일 주소를 입력할 때 debounce를 사용해 입력이 끝난 후 유효성을 검사할 수 있습니다.
const validateEmail = _.debounce((email) => {
const isValid = /\S+@\S+\.\S+/.test(email);
console.log("이메일 유효성: ", isValid);
}, 300);
3.2 무한 스크롤 구현
스크롤 이벤트에 throttle을 적용하여 일정 위치에 도달할 때만 추가 데이터를 로드합니다.
const handleInfiniteScroll = _.throttle(() => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
console.log("추가 데이터 로드");
// 데이터 로드 함수 호출
}
}, 200);
4. 주의사항
- 타이머 관리: debounce와 throttle은 내부적으로 타이머를 사용하기 때문에 컴포넌트가 언마운트될 때 반드시 클린업을 해야 메모리 누수를 방지할 수 있습니다.
- 적절한 시간 설정: 최적화 수준은 이벤트 발생 빈도와 사용자 경험 사이에서 균형을 맞춰야 합니다. 지나치게 짧거나 긴 간격은 문제를 초래할 수 있습니다.
- 의존성 주의: React의 useCallback과 함께 사용할 때, 의존성 배열을 적절히 관리해야 예상치 못한 동작을 방지할 수 있습니다.
5. 결론
React에서 debounce와 throttle은 사용자 경험을 향상시키고 애플리케이션 성능을 최적화하는 데 필수적인 도구입니다. debounce는 사용자 입력처럼 이벤트의 빈도를 줄이는 데, throttle은 스크롤 이벤트처럼 이벤트 실행 간격을 조절하는 데 적합합니다. 이번 글에서 소개한 예제와 실무 사례를 참고하여 여러분의 프로젝트에 적절히 적용해 보세요!
React에서 Accordion 컴포넌트 만들기
Accordion은 클릭 시 콘텐츠가 열리고 닫히는 UI 컴포넌트로, 정보를 계층적으로 보여줄 때 유용합니다. React로 Accordion 컴포넌트를 구현하는 방법을 단계별로 살펴보겠습니다.
1. 기본 구조 설계
Accordion 컴포넌트는 아래와 같은 구조로 구성됩니다:
- Accordion: 여러 개의 패널을 포함하는 부모 컴포넌트.
- AccordionItem: 각각의 패널을 구성하는 개별 컴포넌트.
- AccordionHeader: 패널의 제목 영역.
- AccordionContent: 패널의 내용 영역.
2. Accordion 컴포넌트 구현
2.1 AccordionItem 컴포넌트 작성
Accordion의 각 패널을 관리하는 컴포넌트입니다:
import React, { useState } from "react";
function AccordionItem({ title, children }) {
const [isOpen, setIsOpen] = useState(false);
const toggle = () => setIsOpen(!isOpen);
return (
<div className="accordion-item">
<div className="accordion-header" onClick={toggle}>
<h3>{title}</h3>
<button>{isOpen ? "-" : "+"}</button>
</div>
{isOpen && <div className="accordion-content">{children}</div>}
</div>
);
}
export default AccordionItem;
2.2 Accordion 컴포넌트 작성
AccordionItem을 묶어주는 부모 컴포넌트입니다:
import React from "react";
import AccordionItem from "./AccordionItem";
function Accordion({ items }) {
return (
<div className="accordion">
{items.map((item, index) => (
<AccordionItem key={index} title={item.title}>
{item.content}
</AccordionItem>
))}
</div>
);
}
export default Accordion;
3. 사용 예제
Accordion 컴포넌트를 사용하는 방법은 다음과 같습니다:
import React from "react";
import Accordion from "./Accordion";
const items = [
{ title: "섹션 1", content: "첫 번째 섹션의 내용입니다." },
{ title: "섹션 2", content: "두 번째 섹션의 내용입니다." },
{ title: "섹션 3", content: "세 번째 섹션의 내용입니다." },
];
function App() {
return (
<div className="App">
<h1>Accordion 예제</h1>
<Accordion items={items} />
</div>
);
}
export default App;
4. 스타일링
Accordion의 기본 스타일은 CSS로 작성할 수 있습니다:
.accordion {
border: 1px solid #ccc;
border-radius: 4px;
overflow: hidden;
}
.accordion-item {
border-bottom: 1px solid #ccc;
}
.accordion-header {
display: flex;
justify-content: space-between;
padding: 10px;
cursor: pointer;
background-color: #f9f9f9;
}
.accordion-content {
padding: 10px;
background-color: #fff;
}
5. 결론
React로 Accordion 컴포넌트를 구현하면 동적인 콘텐츠를 효율적으로 관리할 수 있습니다. 이번 글의 예제를 기반으로 자신만의 커스텀 Accordion 컴포넌트를 만들어 보세요!
'React' 카테고리의 다른 글
React에서 Pagination 컴포넌트 만들기 (0) | 2024.12.12 |
---|---|
React에서 Dropdown 컴포넌트 만들기 (0) | 2024.12.12 |
React에서 Tooltip 컴포넌트 만들기 (0) | 2024.12.12 |
React에서 Modal 컴포넌트 만들기 (0) | 2024.12.12 |
React에서 Date Picker 구현하기 (0) | 2024.12.12 |