9화. Lodash, Day.js, Lucide - 유틸리티 모음.zip🧰
안녕하세요🌟 오늘은 프론트엔드 필수 라이브러리 시리즈의 아홉 번째 이야기로, 개발자의 일상을 더 편리하게 만들어주는 유틸리티 라이브러리들인 Lodash, Day.js, Lucide에 대해 알아볼게요! 이 라이브러리들은 작지만 강력한 도구로, 2025년 현재 많은 프론트엔드 개발자들의 필수품이 되었답니다! 🛠️
유틸리티 라이브러리가 필요한 이유 🤔
프론트엔드 개발을 하다 보면 자주 반복되는 작업들이 있어요. 배열이나 객체를 변환하거나, 날짜를 다루거나, 아이콘을 추가하는 일들이 대표적이죠. 이런 작업들을 매번 직접 구현하는 건 시간 낭비일 뿐만 아니라, 버그의 원인이 될 수도 있어요!
유틸리티 라이브러리는 이런 공통 작업들을 검증된 방식으로 처리할 수 있게 해주는 도구예요. 코드의 가독성과 유지보수성을 높이고, 개발 속도도 빨라지죠! 오늘 소개할 세 가지 라이브러리는 각각 데이터 처리, 날짜 조작, UI 아이콘 분야에서 최고의 선택이랍니다!
1. Lodash: 자바스크립트 마법 상자 🧙♂️
Lodash는 JavaScript 개발자를 위한 스위스 아미 나이프 같은 라이브러리예요. 배열, 객체, 문자열 등을 더 쉽고 일관되게 다룰 수 있게 해주죠!
Lodash의 주요 특징:
- 풍부한 유틸리티 함수 📦
- 200개 이상의 모듈화된 함수 제공
- 배열, 객체, 함수, 컬렉션 등 다양한 데이터 처리
- 일관된 크로스 브라우저 지원 🌐
- 브라우저 간 동작 차이 없음
- 안정적인 API 제공
- 모듈화된 구조 🧩
- 필요한 함수만 선택적으로 임포트 가능
- 번들 크기 최적화에 유리
- 성능 최적화 ⚡
- 내부적으로 최적화된 알고리즘 사용
- 대용량 데이터 처리에도 효율적
// Lodash 기본 사용 예시
import _ from 'lodash'; // 전체 라이브러리 가져오기
// 또는 필요한 함수만 가져오기
import { chunk, debounce, uniq } from 'lodash';
// 배열 작업
const numbers = [1, 2, 3, 4, 5, 6];
const chunkedArrays = _.chunk(numbers, 2); // [[1, 2], [3, 4], [5, 6]]
// 중복 제거
const withDuplicates = [1, 1, 2, 3, 3, 3, 4, 5];
const unique = _.uniq(withDuplicates); // [1, 2, 3, 4, 5]
// 객체 다루기
const user = { name: 'John', age: 30, city: 'New York' };
const pickedProps = _.pick(user, ['name', 'city']); // { name: 'John', city: 'New York' }
const omittedProps = _.omit(user, ['age']); // { name: 'John', city: 'New York' }
// 딥 복사
const original = { a: 1, b: { c: 2 } };
const copy = _.cloneDeep(original);
copy.b.c = 3; // original은 변경되지 않음!
// 디바운스 함수 (이벤트 핸들러 최적화)
const handleSearch = _.debounce((searchTerm) => {
// API 호출 등의 비용이 큰 작업
console.log('Searching for:', searchTerm);
}, 300); // 300ms 지연
// 함수 1회만 실행
const initialize = _.once(() => {
console.log('초기화는 한 번만!');
});
Lodash의 핵심 기능 모음:
1. 배열 다루기
// 청크(chunk): 배열을 지정된 크기의 작은 배열로 분할
_.chunk(['a', 'b', 'c', 'd'], 2); // [['a', 'b'], ['c', 'd']]
// 차집합(difference): 첫 번째 배열에는 있지만 다른 배열에는 없는 값 찾기
_.difference([2, 1], [2, 3]); // [1]
// 교집합(intersection): 모든 배열에 공통으로 포함된 값 찾기
_.intersection([2, 1], [2, 3]); // [2]
// 평탄화(flatten/flattenDeep): 중첩 배열 평탄화
_.flatten([1, [2, [3, [4]], 5]]); // [1, 2, [3, [4]], 5]
_.flattenDeep([1, [2, [3, [4]], 5]]); // [1, 2, 3, 4, 5]
// 그룹화(groupBy): 특정 기준으로 그룹 만들기
_.groupBy(['one', 'two', 'three'], 'length'); // { '3': ['one', 'two'], '5': ['three'] }
2. 객체 다루기
// 병합(merge): 객체들을 깊게 병합
_.merge({ a: [1] }, { a: [2, 3] }); // { a: [2, 3] }
// 값 얻기(get): 안전하게 중첩된 객체 속성 접근
const obj = { a: [{ b: { c: 3 } }] };
_.get(obj, 'a[0].b.c'); // 3
_.get(obj, 'a[0].b.d', 'default'); // 'default'
// 키/값 변환
_.keys({ a: 1, b: 2 }); // ['a', 'b']
_.values({ a: 1, b: 2 }); // [1, 2]
_.entries({ a: 1, b: 2 }); // [['a', 1], ['b', 2]]
3. 함수 다루기
// 디바운스(debounce): 함수 호출 제한 (마지막 호출 후 지연 실행)
window.addEventListener('resize', _.debounce(() => {
console.log('리사이즈 완료!');
}, 300));
// 쓰로틀(throttle): 함수 호출 제한 (일정 시간마다 한 번씩 실행)
window.addEventListener('scroll', _.throttle(() => {
console.log('스크롤 중...');
}, 200));
// 커링(curry): 함수의 인자를 부분적으로 적용
const greet = _.curry((greeting, name) => `${greeting}, ${name}!`);
const sayHello = greet('Hello');
sayHello('John'); // 'Hello, John!'
4. 유틸리티 함수
// 딥 이퀄(isEqual): 깊은 비교
_.isEqual([1, 2, 3], [1, 2, 3]); // true
// 랜덤(random): 난수 생성
_.random(1, 10); // 1과 10 사이 랜덤 숫자
// 유니크 ID(uniqueId): 고유 ID 생성
_.uniqueId('prefix_'); // 'prefix_1', 'prefix_2' 등
// 횟수만큼 반복(times): 함수를 n번 실행
_.times(3, i => i); // [0, 1, 2]
2025년 Lodash의 최신 기능:
- 트리 셰이킹 향상: 개별 함수 임포트 시 번들 최적화 강화
- 타입스크립트 지원 개선: 더 정확한 타입 정의 및 추론
- 성능 개선: 내부 알고리즘 추가 최적화
- ESM 지원 강화: 네이티브 ES 모듈 지원 향상
2. Day.js: 가벼운 날짜 마술사 📅
Day.js는 Moment.js의 가벼운 대안으로 탄생한 날짜 조작 라이브러리예요. 2KB 미만의 크기로 강력한 날짜/시간 기능을 제공한답니다!
Day.js의 주요 특징:
- 초경량 사이즈 🪶
- 2KB 미만의 작은 번들 크기
- 빠른 로딩 속도
- 호환성 🤝
- Moment.js와 유사한 API (쉬운 마이그레이션)
- 모든 브라우저 지원
- 불변성 🧊
- 원본 객체를 변경하지 않는 불변 설계
- 예측 가능한 동작
- 플러그인 시스템 🔌
- 필요한 기능만 선택적으로 추가
- 사용하지 않는 기능은 번들에 포함되지 않음
// Day.js 기본 사용 예시
import dayjs from 'dayjs';
// 현재 날짜/시간
const now = dayjs();
console.log(now.format('YYYY-MM-DD HH:mm:ss')); // '2025-04-17 15:30:00'
// 특정 날짜 생성
const christmas = dayjs('2025-12-25');
console.log(christmas.format('MMMM D, YYYY')); // 'December 25, 2025'
// 날짜 조작
const tomorrow = dayjs().add(1, 'day');
const lastWeek = dayjs().subtract(1, 'week');
const startOfMonth = dayjs().startOf('month');
const endOfYear = dayjs().endOf('year');
// 날짜 비교
const isBefore = dayjs().isBefore(christmas); // true
const isSame = dayjs().isSame(dayjs(), 'day'); // true (같은 날)
const diff = christmas.diff(dayjs(), 'day'); // 크리스마스까지 남은 일수
Day.js의 유용한 플러그인:
1. 상대 시간 (RelativeTime)
// 플러그인 등록
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/ko'; // 한국어 로케일
dayjs.extend(relativeTime);
dayjs.locale('ko'); // 한국어 설정
// 상대 시간 표시
dayjs().to(dayjs().add(1, 'hour')); // '1시간 후'
dayjs().from(dayjs().subtract(30, 'minute')); // '30분 전'
2. 지역화 (Localization)
import dayjs from 'dayjs';
import 'dayjs/locale/ko';
import 'dayjs/locale/ja';
import 'dayjs/locale/en';
// 로케일 변경
dayjs.locale('ko');
dayjs().format('YYYY년 MMMM D일'); // '2025년 4월 17일'
dayjs.locale('ja');
dayjs().format('YYYY年 MMMM D日'); // '2025年 4月 17日'
dayjs.locale('en');
dayjs().format('MMMM D, YYYY'); // 'April 17, 2025'
3. 분기 (QuarterOfYear)
import dayjs from 'dayjs';
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
dayjs.extend(quarterOfYear);
// 분기 관련 기능
const quarter = dayjs().quarter(); // 현재 분기 (1-4)
const startOfQuarter = dayjs().startOf('quarter'); // 분기의 시작
const endOfQuarter = dayjs().endOf('quarter'); // 분기의 끝
// 특정 분기로 설정
const q3Start = dayjs().quarter(3).startOf('quarter'); // 3분기 시작
4. 캘린더 (Calendar)
import dayjs from 'dayjs';
import calendar from 'dayjs/plugin/calendar';
dayjs.extend(calendar);
// 캘린더 형식 출력 (상황에 맞는 날짜 표현)
dayjs().calendar(null, {
sameDay: '[오늘] HH:mm', // 같은 날
nextDay: '[내일] HH:mm', // 다음 날
nextWeek: 'dddd HH:mm', // 다음 주
lastDay: '[어제] HH:mm', // 이전 날
lastWeek: '[지난] dddd HH:mm', // 지난 주
sameElse: 'YYYY-MM-DD HH:mm' // 그 외
});
// 결과 예: '오늘 15:30' 또는 '내일 09:00' 등
실전 사용 예시:
1. 날짜 선택기 (Date Picker)
// Day.js 기반 날짜 선택 UI 로직
function DatePicker({ onChange, value }) {
const [date, setDate] = useState(value ? dayjs(value) : dayjs());
const handlePrevMonth = () => {
setDate(date.subtract(1, 'month'));
};
const handleNextMonth = () => {
setDate(date.add(1, 'month'));
};
const handleDateSelect = (day) => {
const newDate = date.date(day);
setDate(newDate);
onChange(newDate.toDate());
};
// 현재 월의 날짜 그리드 생성
const daysInMonth = date.daysInMonth();
const firstDayOfMonth = date.startOf('month').day();
// 달력 UI 렌더링 로직...
return (
<div className="date-picker">
<div className="header">
<button onClick={handlePrevMonth}>◀</button>
<h2>{date.format('YYYY년 MM월')}</h2>
<button onClick={handleNextMonth}>▶</button>
</div>
{/* 요일 헤더 */}
<div className="weekdays">
{['일', '월', '화', '수', '목', '금', '토'].map(day => (
<div key={day} className="day-name">{day}</div>
))}
</div>
{/* 날짜 그리드 */}
<div className="days-grid">
{/* 빈 셀 */}
{Array.from({ length: firstDayOfMonth }).map((_, i) => (
<div key={`empty-${i}`} className="day empty"></div>
))}
{/* 날짜 셀 */}
{Array.from({ length: daysInMonth }).map((_, i) => (
<div
key={`day-${i+1}`}
className={`day ${date.date() === i+1 ? 'selected' : ''}`}
onClick={() => handleDateSelect(i+1)}
>
{i+1}
</div>
))}
</div>
</div>
);
}
2. 시간대 변환기
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
dayjs.extend(utc);
dayjs.extend(timezone);
function TimeConverter() {
const [selectedTime, setSelectedTime] = useState(dayjs());
const [selectedTimezone, setSelectedTimezone] = useState('Asia/Seoul');
const timezones = [
{ value: 'Asia/Seoul', label: '서울 (KST)' },
{ value: 'America/New_York', label: '뉴욕 (EST/EDT)' },
{ value: 'Europe/London', label: '런던 (GMT/BST)' },
{ value: 'Europe/Paris', label: '파리 (CET/CEST)' },
{ value: 'Asia/Tokyo', label: '도쿄 (JST)' },
];
const convertedTimes = timezones.map(tz => ({
timezone: tz.label,
time: dayjs(selectedTime).tz(tz.value).format('YYYY-MM-DD HH:mm:ss')
}));
return (
<div className="time-converter">
<h2>시간대 변환기</h2>
<div className="input-group">
<input
type="datetime-local"
value={selectedTime.format('YYYY-MM-DDTHH:mm')}
onChange={(e) => setSelectedTime(dayjs(e.target.value))}
/>
<select
value={selectedTimezone}
onChange={(e) => setSelectedTimezone(e.target.value)}
>
{timezones.map(tz => (
<option key={tz.value} value={tz.value}>{tz.label}</option>
))}
</select>
</div>
<div className="converted-times">
<h3>변환된 시간</h3>
<ul>
{convertedTimes.map(ct => (
<li key={ct.timezone}>
<strong>{ct.timezone}:</strong> {ct.time}
</li>
))}
</ul>
</div>
</div>
);
}
2025년 Day.js의 최신 기능:
- 타임존 지원 향상: 더 정확한 시간대 처리
- 날짜 계산 확장: 더 다양한 날짜 계산 유틸리티
- 로컬라이제이션 개선: 더 많은 언어와 지역 형식 지원
- 성능 최적화: 내부 처리 속도 향상
3. Lucide: 아름다운 아이콘의 집합 🎨
Lucide는 오픈 소스 아이콘 라이브러리로, 다양한 프레임워크와 통합하여 사용할 수 있는 깔끔하고 일관된 아이콘을 제공해요!
Lucide의 주요 특징:
- 다양한 아이콘 세트 🎭
- 1000개 이상의 아이콘 포함
- 일관된 디자인 시스템
- 프레임워크 통합 ⚛️
- React, Vue, Svelte 등 다양한 프레임워크 지원
- 네이티브 컴포넌트처럼 사용 가능
- 사용자 정의 가능 🎛️
- 색상, 크기, 스트로크 등 쉽게 커스터마이징
- 프로젝트 요구 사항에 맞게 조정 가능
- 접근성 중시 ♿
- 접근성 표준 준수
- ARIA 속성 자동 추가
// React에서 Lucide 사용 예시
import { Heart, MessageCircle, Share2 } from 'lucide-react';
function SocialButtons() {
return (
<div className="social-buttons">
<button className="like-button">
<Heart size={24} color="red" /> 좋아요
</button>
<button className="comment-button">
<MessageCircle size={24} /> 댓글
</button>
<button className="share-button">
<Share2 size={24} /> 공유
</button>
</div>
);
}
Lucide 활용 팁:
1. 스타일 커스터마이징
// 아이콘 스타일 커스터마이징
import { AlertCircle } from 'lucide-react';
// 기본 속성 변경
<AlertCircle size={32} color="#ff6b6b" strokeWidth={1.5} />
// CSS 클래스 적용
<AlertCircle className="alert-icon pulse-animation" />
// 인라인 스타일 적용
<AlertCircle style={{ filter: 'drop-shadow(0 0 5px rgba(255, 0, 0, 0.5))' }} />
2. 인터랙션 연결
// 아이콘에 인터랙션 추가
import { Bell, BellOff } from 'lucide-react';
import { useState } from 'react';
function NotificationToggle() {
const [enabled, setEnabled] = useState(false);
return (
<button
onClick={() => setEnabled(!enabled)}
aria-label={enabled ? '알림 끄기' : '알림 켜기'}
className="notification-toggle"
>
{enabled ? (
<Bell size={24} className="bell-icon active" />
) : (
<BellOff size={24} className="bell-icon" />
)}
</button>
);
}
3. 애니메이션 적용
// CSS 애니메이션과 함께 사용
import { RefreshCw } from 'lucide-react';
// CSS
/*
.loading-icon {
animation: spin 1.5s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
*/
function LoadingButton({ isLoading, onClick, children }) {
return (
<button
onClick={onClick}
disabled={isLoading}
className="loading-button"
>
{isLoading ? (
<>
<RefreshCw className="loading-icon" size={18} />
로딩 중...
</>
) : (
children
)}
</button>
);
}
4. 아이콘 사용 패턴화
// 일관된 아이콘 사용을 위한 래퍼 컴포넌트
import * as LucideIcons from 'lucide-react';
// 기본 아이콘 래퍼 컴포넌트
function Icon({ name, size = 24, color = 'currentColor', ...props }) {
const LucideIcon = LucideIcons[name];
if (!LucideIcon) {
console.warn(`Icon "${name}" not found in Lucide icons`);
return null;
}
return <LucideIcon size={size} color={color} {...props} />;
}
// 사용 예
function App() {
return (
<div>
<Icon name="Home" />
<Icon name="Settings" size={32} color="blue" />
<Icon name="User" className="user-icon" />
</div>
);
}
실전 사용 예시:
1. 아이콘 갤러리 컴포넌트
// 사용 가능한 모든 아이콘을 갤러리로 표시
import * as icons from 'lucide-react';
import { useState } from 'react';
function IconGallery() {
const [search, setSearch] = useState('');
const [selectedIcon, setSelectedIcon] = useState(null);
// Object.entries()를 사용하여 모든 아이콘 컴포넌트 가져오기
// 'Lucide' 컴포넌트는 제외
const iconList = Object.entries(icons)
.filter(([name]) => name !== 'Lucide')
.filter(([name]) =>
search === '' || name.toLowerCase().includes(search.toLowerCase())
);
return (
<div className="icon-gallery">
<div className="search-bar">
<input
type="text"
placeholder="아이콘 검색..."
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
</div>
{selectedIcon && (
<div className="selected-icon">
<h2>{selectedIcon.name}</h2>
<div className="icon-preview">
{React.createElement(selectedIcon.component, { size: 48 })}
</div>
<pre>
{`import { ${selectedIcon.name} } from 'lucide-react';`}
</pre>
</div>
)}
<div className="icons-grid">
{iconList.map(([name, Icon]) => (
<div
key={name}
className="icon-item"
onClick={() => setSelectedIcon({ name, component: Icon })}
>
<Icon size={24} />
<span className="icon-name">{name}</span>
</div>
))}
</div>
{iconList.length === 0 && (
<p className="no-results">검색 결과가 없습니다.</p>
)}
</div>
);
}
2. 인터랙티브 내비게이션 메뉴
// 아이콘 기반 네비게이션 메뉴
import { Home, User, Settings, HelpCircle, LogOut } from 'lucide-react';
import { useState } from 'react';
function Sidebar() {
const [activeItem, setActiveItem] = useState('home');
const menuItems = [
{ id: 'home', icon: Home, label: '홈' },
{ id: 'profile', icon: User, label: '프로필' },
{ id: 'settings', icon: Settings, label: '설정' },
{ id: 'help', icon: HelpCircle, label: '도움말' },
];
return (
<div className="sidebar">
<div className="menu-items">
{menuItems.map(item => (
<button
key={item.id}
className={`menu-item ${activeItem === item.id ? 'active' : ''}`}
onClick={() => setActiveItem(item.id)}
>
<item.icon size={activeItem === item.id ? 24 : 20} />
<span className="menu-label">{item.label}</span>
</button>
))}
</div>
<div className="sidebar-footer">
<button className="logout-button">
<LogOut size={20} />
<span>로그아웃</span>
</button>
</div>
</div>
);
}
2025년 Lucide의 최신 기능:
- 카테고리 시스템: 주제별로 그룹화된 아이콘 세트
- 애니메이션 옵션: 내장 애니메이션 지원 강화
- 추가 아이콘: 일관된 디자인의 새 아이콘 추가
- 색상 테마 지원: 다크/라이트 모드 자동 지원
세 라이브러리의 조합: 개발 효율성의 극대화 💯
이 세 라이브러리를 함께 사용하면 개발 효율성이 크게 향상돼요! 실제 프로젝트에서 어떻게 조합할 수 있는지 예시를 통해 살펴볼게요.
// 데이터 대시보드 컴포넌트 예시
import { useState, useEffect } from 'react';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/ko';
import { Calendar, BarChart2, RefreshCw, Download } from 'lucide-react';
import _ from 'lodash';
// Day.js 설정
dayjs.extend(relativeTime);
dayjs.locale('ko');
function DataDashboard({ data }) {
const [timeRange, setTimeRange] = useState('week');
const [filteredData, setFilteredData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
// Lodash로 데이터 처리
useEffect(() => {
setIsLoading(true);
// 날짜 범위에 따라 데이터 필터링
const startDate = dayjs().subtract(1, timeRange).startOf('day');
const filtered = data.filter(item =>
dayjs(item.timestamp).isAfter(startDate)
);
// 데이터 변환 및 그룹화
const processedData = _.chain(filtered)
// 날짜별로 그룹화
.groupBy(item => dayjs(item.timestamp).format('YYYY-MM-DD'))
// 각 그룹에 대해 합계 계산
.map((items, date) => ({
date,
value: _.sumBy(items, 'value'),
count: items.length
}))
// 날짜순 정렬
.sortBy('date')
.value();
setFilteredData(processedData);
setIsLoading(false);
}, [data, timeRange]);
// 데이터 다운로드 핸들러 (Lodash 활용)
const handleDownload = () => {
// CSV 데이터 생성
const headers = 'Date,Value,Count\n';
const csvContent = filteredData.reduce((acc, row) => {
return acc + `${row.date},${row.value},${row.count}\n`;
}, headers);
// 다운로드 링크 생성
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', `dashboard-${dayjs().format('YYYY-MM-DD')}.csv`);
link.click();
};
return (
<div className="dashboard">
<div className="dashboard-header">
<h1>데이터 대시보드</h1>
<div className="date-filter">
<Calendar size={18} />
<select
value={timeRange}
onChange={e => setTimeRange(e.target.value)}
>
<option value="day">오늘</option>
<option value="week">이번 주</option>
<option value="month">이번 달</option>
<option value="year">올해</option>
</select>
</div>
<div className="actions">
<button className="refresh-btn" onClick={() => setIsLoading(true)}>
<RefreshCw size={18} className={isLoading ? 'spinning' : ''} />
새로고침
</button>
<button className="download-btn" onClick={handleDownload}>
<Download size={18} />
다운로드
</button>
</div>
</div>
<div className="dashboard-content">
{isLoading ? (
<div className="loading">
<RefreshCw size={32} className="spinning" />
<p>데이터 로딩 중...</p>
</div>
) : filteredData.length === 0 ? (
<div className="no-data">
<BarChart2 size={32} />
<p>선택한 기간에 데이터가 없습니다.</p>
</div>
) : (
<div className="dashboard-charts">
<div className="summary-cards">
<div className="card total-value">
<h3>총 값</h3>
<p className="value">{_.sumBy(filteredData, 'value').toLocaleString()}</p>
</div>
<div className="card total-count">
<h3>총 건수</h3>
<p className="value">{_.sumBy(filteredData, 'count').toLocaleString()}</p>
</div>
<div className="card average">
<h3>평균</h3>
<p className="value">
{(_.sumBy(filteredData, 'value') / filteredData.length).toFixed(2)}
</p>
</div>
<div className="card last-update">
<h3>마지막 업데이트</h3>
<p className="value">
{dayjs(_.last(filteredData)?.date).fromNow()}
</p>
</div>
</div>
{/* 여기에 차트 컴포넌트 */}
<div className="chart-container">
{/* 차트 라이브러리 사용 */}
</div>
<div className="data-table">
<h3>상세 데이터</h3>
<table>
<thead>
<tr>
<th>날짜</th>
<th>값</th>
<th>건수</th>
</tr>
</thead>
<tbody>
{filteredData.map(item => (
<tr key={item.date}>
<td>{dayjs(item.date).format('YYYY년 MM월 DD일')}</td>
<td>{item.value.toLocaleString()}</td>
<td>{item.count.toLocaleString()}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
</div>
</div>
);
}
유틸리티 라이브러리를 더 효과적으로 사용하는 팁 💡
1. 번들 크기 최적화
// ❌ 전체 라이브러리 가져오기 (피해야 함)
import _ from 'lodash';
// ✅ 필요한 함수만 가져오기 (권장)
import { debounce, uniq, groupBy } from 'lodash';
// 또는
import debounce from 'lodash/debounce';
import uniq from 'lodash/uniq';
import groupBy from 'lodash/groupBy';
2. 일관된 네이밍 규칙 적용
// 팀 내에서 일관된 네이밍 컨벤션 사용하기
// 예: Day.js 날짜 포맷팅 함수
function formatDate(date, format = 'YYYY-MM-DD') {
return dayjs(date).format(format);
}
function formatDateRelative(date) {
return dayjs(date).fromNow();
}
// 아이콘 컴포넌트 래핑
function AppIcon({ name, ...props }) {
const IconComponent = icons[name];
return IconComponent ? <IconComponent {...props} /> : null;
}
3. Custom Hooks로 추상화
// 디바운스 Hook
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = _.debounce(() => {
setDebouncedValue(value);
}, delay);
handler();
return () => {
handler.cancel();
};
}, [value, delay]);
return debouncedValue;
}
// 날짜 범위 Hook
function useDateRange(initialRange = 'week') {
const [range, setRange] = useState(initialRange);
const dateRange = useMemo(() => {
const end = dayjs();
let start;
switch (range) {
case 'day':
start = end.startOf('day');
break;
case 'week':
start = end.subtract(1, 'week');
break;
case 'month':
start = end.subtract(1, 'month');
break;
case 'year':
start = end.subtract(1, 'year');
break;
default:
start = end.subtract(1, 'week');
}
return { start, end };
}, [range]);
return [dateRange, setRange];
}
마무리 🎁
Lodash, Day.js, Lucide는 작지만 강력한 유틸리티 라이브러리로, 프론트엔드 개발의 효율성과 품질을 크게 향상시킬 수 있어요. 이 라이브러리들은 각각 데이터 처리, 날짜 조작, UI 아이콘이라는 특화된 영역에서 뛰어난 기능을 제공하며, 함께 사용하면 시너지 효과를 낼 수 있답니다!
- Lodash: 복잡한 데이터 처리를 간결하고 효율적으로
- Day.js: 날짜와 시간을 쉽고 가볍게
- Lucide: 아름답고 일관된 아이콘으로 UI 향상
이 세 라이브러리를 숙지하고 적절히 활용한다면, 코드의 가독성, 유지보수성, 성능이 모두 향상되고 개발 시간도 크게 단축될 거예요!
다음 시간에는 테스트의 세계로 들어가 Jest, React Testing Library, Cypress에 대해 알아볼 예정이니 기대해주세요! 🧪
여러분의 개발이 더욱 즐겁고 효율적이길 바랍니다! 😄👋
'개발' 카테고리의 다른 글
프론트 필수 라이브러리 모음 : 11화. NextAuth.js, Clerk - 인증 솔루션🧩✨ (0) | 2025.04.27 |
---|---|
프론트 필수 라이브러리 모음 : 10화 Jest, React Testing Library, Cypress - 테스트 자동화🧩✨ (0) | 2025.04.26 |
프론트 필수 라이브러리 모음 : 8화 TanStack Query & SWR - 데이터 통신과 서버 상태 관리🧩✨ (0) | 2025.04.24 |
프론트 필수 라이브러리 모음 : 7화 Zustand & Jotai & Redux - 상태 관리 비교 🧩✨ (0) | 2025.04.23 |
프론트 필수 라이브러리 모음 : 6화. React Hook Form & Zod - 폼과 유효성 검증🧩✨ (0) | 2025.04.22 |