React + TypeScript로 축제 리스트 무한 스크롤 최적화하기
2025. 5. 25. 16:12ㆍ프론트엔드/TypeScript
728x90
최근 축제 정보를 제공하는 웹 서비스에서 무한 스크롤을 구현하던 중, 중복 데이터 렌더링 문제와 옵저버 재생성으로 인한 성능 저하, TypeScript의 타입 오류 등 다양한 문제를 경험했습니다. 이번 글에서는 실제 프로젝트에서 겪은 문제 상황과 그에 대한 해결 과정을 개발 회고 형식으로 정리해보려 합니다.
🧩 문제 상황 요약
초기에는 다음과 같은 형태로 데이터를 페이징하여 불러왔습니다:
const loadFestivals = useCallback(async () => {
const today = formatDate(new Date());
const response = await axiosInstance.get('/api/event', {
params: { startDate: today, endDate: today, page, size: 5 },
});
setFestivals(prev => [...prev, ...response.data.data.content]);
}, [page]);
하지만 아래와 같은 문제가 나타났습니다:
- 동일한 데이터가 여러 번 누적되어 렌더링되는 중복 문제
- IntersectionObserver가 매번 재생성되며 성능 저하 유발
- TypeScript strict 모드에서 발생하는 any 타입 관련 오류
🔧 해결 과정
1. 중복 데이터 필터링 로직 추가
축제 데이터 중 eventId 기준으로 이미 등록된 항목은 제외하고 새로운 데이터만 추가되도록 개선했습니다:
setFestivals(prev => {
const existingIds = new Set(prev.map((f: Festival) => f.eventId));
const filtered = newEvents.filter((f: Festival) => !existingIds.has(f.eventId));
return [...prev, ...filtered];
});
이로써 동일한 페이지 데이터를 여러 번 불러오더라도 UI에는 중복 표시되지 않게 되었습니다.
2. useCallback 의존성 최적화
함수 내부에서 page를 참조하는 방식은 useCallback 재생성을 유발했습니다. 이를 함수 인자로 분리해 해결했습니다:
const loadFestivals = useCallback(async (pageToLoad: number) => {
const today = formatDate(new Date());
const response = await axiosInstance.get('/api/event', {
params: { startDate: today, endDate: today, page: pageToLoad, size: 5 },
});
// 중복 필터링 로직 포함
}, []);
useEffect(() => {
loadFestivals(page);
}, [page]);
3. TypeScript 오류 해결
다음과 같은 오류 메시지가 떴습니다:
Parameter 'f' implicitly has an 'any' type.ts(7006)
이는 map이나 filter의 매개변수 타입을 명시하지 않았기 때문이었습니다. 아래와 같이 Festival 타입을 명시해 해결했습니다:
prev.map((f: Festival) => f.eventId);
newEvents.filter((f: Festival) => !existingIds.has(f.eventId));
✅ 리팩토링 결과 및 성과
- 중복 데이터 제거: 렌더링 성능 및 UX 개선
- 함수 재사용 최적화: 불필요한 옵저버 재설정 방지
- TypeScript 안정성 향상: 코드 가독성과 유지보수성 향상
728x90
'프론트엔드 > TypeScript' 카테고리의 다른 글
| error 타입 모듈 AxiosError (1) | 2025.05.09 |
|---|