perf: Schedule 페이지 성능 최적화
- useDeferredValue로 달력 점 표시 지연 처리 - scheduleDateMap으로 O(1) 조회 최적화 - selectedDate 변경 시 스크롤 맨 위로 초기화
This commit is contained in:
parent
8db0a574ab
commit
2b6fa74eb8
1 changed files with 28 additions and 6 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState, useEffect, useRef, useMemo } from 'react';
|
import { useState, useEffect, useRef, useMemo, useDeferredValue, memo } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
import { Clock, ChevronLeft, ChevronRight, ChevronDown, Tag, Search, ArrowLeft, Link2 } from 'lucide-react';
|
import { Clock, ChevronLeft, ChevronRight, ChevronDown, Tag, Search, ArrowLeft, Link2 } from 'lucide-react';
|
||||||
|
|
@ -26,6 +26,7 @@ function Schedule() {
|
||||||
// 카테고리 필터 툴팁
|
// 카테고리 필터 툴팁
|
||||||
const [showCategoryTooltip, setShowCategoryTooltip] = useState(false);
|
const [showCategoryTooltip, setShowCategoryTooltip] = useState(false);
|
||||||
const categoryRef = useRef(null);
|
const categoryRef = useRef(null);
|
||||||
|
const scrollContainerRef = useRef(null); // 일정 목록 스크롤 컨테이너
|
||||||
|
|
||||||
// 검색 상태
|
// 검색 상태
|
||||||
const [isSearchMode, setIsSearchMode] = useState(false);
|
const [isSearchMode, setIsSearchMode] = useState(false);
|
||||||
|
|
@ -128,6 +129,13 @@ function Schedule() {
|
||||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// 날짜 변경 시 스크롤 맨 위로 초기화
|
||||||
|
useEffect(() => {
|
||||||
|
if (scrollContainerRef.current) {
|
||||||
|
scrollContainerRef.current.scrollTop = 0;
|
||||||
|
}
|
||||||
|
}, [selectedDate]);
|
||||||
|
|
||||||
// 달력 관련 함수
|
// 달력 관련 함수
|
||||||
const getDaysInMonth = (year, month) => new Date(year, month + 1, 0).getDate();
|
const getDaysInMonth = (year, month) => new Date(year, month + 1, 0).getDate();
|
||||||
const getFirstDayOfMonth = (year, month) => new Date(year, month, 1).getDay();
|
const getFirstDayOfMonth = (year, month) => new Date(year, month, 1).getDay();
|
||||||
|
|
@ -139,21 +147,34 @@ function Schedule() {
|
||||||
|
|
||||||
const days = ['일', '월', '화', '수', '목', '금', '토'];
|
const days = ['일', '월', '화', '수', '목', '금', '토'];
|
||||||
|
|
||||||
// 스케줄이 있는 날짜 목록 (ISO 형식에서 YYYY-MM-DD 추출)
|
// 스케줄 데이터를 지연 처리하여 달력 UI 응답성 향상
|
||||||
const scheduleDates = schedules.map(s => s.date ? s.date.split('T')[0] : '');
|
const deferredSchedules = useDeferredValue(schedules);
|
||||||
|
|
||||||
// 해당 날짜의 첫 번째 일정 카테고리 색상
|
// 일정 날짜별 맵 (O(1) 조회용) - 지연된 데이터로 점 표시
|
||||||
|
const scheduleDateMap = useMemo(() => {
|
||||||
|
const map = new Map();
|
||||||
|
deferredSchedules.forEach(s => {
|
||||||
|
const dateStr = s.date ? s.date.split('T')[0] : '';
|
||||||
|
if (!map.has(dateStr)) {
|
||||||
|
map.set(dateStr, s);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
}, [deferredSchedules]);
|
||||||
|
|
||||||
|
// 해당 날짜의 첫 번째 일정 카테고리 색상 (O(1))
|
||||||
const getScheduleColor = (day) => {
|
const getScheduleColor = (day) => {
|
||||||
const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
||||||
const schedule = schedules.find(s => (s.date ? s.date.split('T')[0] : '') === dateStr);
|
const schedule = scheduleDateMap.get(dateStr);
|
||||||
if (!schedule) return null;
|
if (!schedule) return null;
|
||||||
const cat = categories.find(c => c.id === schedule.category_id);
|
const cat = categories.find(c => c.id === schedule.category_id);
|
||||||
return cat?.color || '#4A7C59';
|
return cat?.color || '#4A7C59';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 해당 날짜에 일정이 있는지 확인 (O(1))
|
||||||
const hasSchedule = (day) => {
|
const hasSchedule = (day) => {
|
||||||
const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
||||||
return scheduleDates.includes(dateStr);
|
return scheduleDateMap.has(dateStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
const prevMonth = () => {
|
const prevMonth = () => {
|
||||||
|
|
@ -768,6 +789,7 @@ function Schedule() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
ref={scrollContainerRef}
|
||||||
id="scheduleScrollContainer"
|
id="scheduleScrollContainer"
|
||||||
className="max-h-[calc(100vh-200px)] overflow-y-auto space-y-4 py-2 pr-2"
|
className="max-h-[calc(100vh-200px)] overflow-y-auto space-y-4 py-2 pr-2"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue