사용자가 원하는 기준으로 상품을 정렬해서 볼 수 있는 기능은 쇼핑몰의 사용자 경험을 크게 향상시킵니다.
오늘은 정렬(Sort) 기능(상품 가격을 기준으로 내림차순, 오름차순) 구현에 필요한 JavaScript 핵심 문법을 알아보겠습니다.
1. 배열의 sort() 메서드 기본
sort() 메서드는 배열의 요소를 정렬합니다. 기본적으로 문자열 순서로 정렬됩니다.
기본 문법
array.sort((a, b) => {
// a가 b보다 앞에 오려면 음수 반환
// a가 b 뒤에 오려면 양수 반환
// 순서를 바꾸지 않으려면 0 반환
});
주의사항
const numbers = [1, 30, 4, 21, 100000];
// 잘못된 사용 - 문자열로 정렬됨
numbers.sort();
console.log(numbers); // [1, 100000, 21, 30, 4]
// 올바른 사용 - 숫자로 정렬
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 4, 21, 30, 100000]
2. 숫자 정렬
오름차순 정렬
const prices = [100, 50, 200, 25, 150];
// 가격 낮은 순
const ascending = [...prices].sort((a, b) => a - b);
console.log(ascending); // [25, 50, 100, 150, 200]
내림차순 정렬
// 가격 높은 순
const descending = [...prices].sort((a, b) => b - a);
console.log(descending); // [200, 150, 100, 50, 25]
왜 스프레드 연산자를?
원본 배열을 유지하고, 순서를 변경한 값을 새로운 배열에 할당하기 위해서 사용합니다.
// sort()는 원본 배열을 변경합니다!
const original = [3, 1, 2];
original.sort(); // [1, 2, 3]
console.log(original); // [1, 2, 3] - 원본이 변경됨!
// 원본을 보존하려면 복사본에 정렬
const copy = [...original].sort();
3. 객체 배열 정렬
쇼핑몰 상품 데이터는 대부분 객체 배열입니다.
가격으로 정렬
const products = [
{ id: 1, name: '노트북', price: 1000 },
{ id: 2, name: '마우스', price: 30 },
{ id: 3, name: '키보드', price: 70 },
{ id: 4, name: '모니터', price: 300 }
];
// 가격 낮은 순
const byPriceAsc = [...products].sort((a, b) => a.price - b.price);
// 가격 높은 순
const byPriceDesc = [...products].sort((a, b) => b.price - a.price);
이름으로 정렬
// 이름 가나다순
const byNameAsc = [...products].sort((a, b) =>
a.name.localeCompare(b.name)
);
// 이름 역순
const byNameDesc = [...products].sort((a, b) =>
b.name.localeCompare(a.name)
);
4. React에서 정렬 구현하기
import { useState, useEffect } from 'react';
function ProductSort() {
const [products, setProducts] = useState([]);
const [sortOption, setSortOption] = useState('default');
// 상품 데이터 가져오기
useEffect(() => {
fetch('https://fakestoreapi.com/products')
.then(res => res.json())
.then(data => setProducts(data));
}, []);
// 정렬된 상품 계산
const getSortedProducts = () => {
const sorted = [...products]; // 원본 보존
switch (sortOption) {
case 'price-asc':
return sorted.sort((a, b) => a.price - b.price);
case 'price-desc':
return sorted.sort((a, b) => b.price - a.price);
case 'name-asc':
return sorted.sort((a, b) => a.title.localeCompare(b.title));
case 'name-desc':
return sorted.sort((a, b) => b.title.localeCompare(a.title));
case 'rating':
return sorted.sort((a, b) => b.rating.rate - a.rating.rate);
default:
return sorted; // 기본 순서
}
};
const sortedProducts = getSortedProducts();
return (
{sortedProducts.map(product => ( ))}
);
}
5. localeCompare()로 문자열 비교
localeCompare()는 언어 규칙에 맞게 문자열을 비교합니다.
// 한글 정렬
const names = ['홍길동', '김철수', '이영희'];
const sorted = names.sort((a, b) => a.localeCompare(b, 'ko'));
console.log(sorted); // ['김철수', '이영희', '홍길동']
// 영문 정렬 (대소문자 무시)
const products = ['Apple', 'banana', 'Cherry'];
const sorted2 = products.sort((a, b) =>
a.localeCompare(b, 'en', { sensitivity: 'base' })
);
console.log(sorted2); // ['Apple', 'banana', 'Cherry']
6. 복잡한 정렬 조건
여러 조건으로 정렬
const products = [
{ name: '노트북', category: 'electronics', price: 1000 },
{ name: '마우스', category: 'electronics', price: 30 },
{ name: '셔츠', category: 'clothing', price: 50 },
{ name: '청바지', category: 'clothing', price: 80 }
];
// 카테고리별로 먼저 정렬, 같은 카테고리 내에서는 가격순
const sorted = [...products].sort((a, b) => {
// 1순위: 카테고리
const categoryCompare = a.category.localeCompare(b.category);
if (categoryCompare !== 0) {
return categoryCompare;
}
// 2순위: 가격
return a.price - b.price;
});
console.log(sorted);
// clothing 카테고리가 먼저 나오고, 그 안에서 가격순
날짜로 정렬
const reviews = [
{ text: '좋아요', date: new Date('2024-01-15') },
{ text: '별로에요', date: new Date('2024-01-10') },
{ text: '최고!', date: new Date('2024-01-20') }
];
// 최신순
const newest = [...reviews].sort((a, b) => b.date - a.date);
// 오래된 순
const oldest = [...reviews].sort((a, b) => a.date - b.date);
7. 성능 최적화: useMemo 활용
정렬은 비용이 큰 작업입니다. useMemo로 최적화하세요.
import { useMemo } from 'react';
function OptimizedSort() {
const [products, setProducts] = useState([]);
const [sortOption, setSortOption] = useState('default');
// sortOption이나 products가 변경될 때만 재계산
const sortedProducts = useMemo(() => {
console.log('정렬 계산 실행');
const sorted = [...products];
switch (sortOption) {
case 'price-asc':
return sorted.sort((a, b) => a.price - b.price);
case 'price-desc':
return sorted.sort((a, b) => b.price - a.price);
default:
return sorted;
}
}, [products, sortOption]);
return <ProductList products={sortedProducts} />;
}
8. 버튼으로 정렬 토글
같은 버튼을 누르면 오름차순/내림차순이 토글되는 UX입니다.
function SortToggle() {
const [products, setProducts] = useState([]);
const [sortConfig, setSortConfig] = useState({
key: null,
direction: 'asc'
});
const handleSort = (key) => {
let direction = 'asc';
// 같은 키를 다시 클릭하면 방향 전환
if (sortConfig.key === key && sortConfig.direction === 'asc') {
direction = 'desc';
}
setSortConfig({ key, direction });
};
const sortedProducts = useMemo(() => {
const sorted = [...products];
if (sortConfig.key) {
sorted.sort((a, b) => {
const aValue = a[sortConfig.key];
const bValue = b[sortConfig.key];
if (typeof aValue === 'string') {
return sortConfig.direction === 'asc'
? aValue.localeCompare(bValue)
: bValue.localeCompare(aValue);
}
return sortConfig.direction === 'asc'
? aValue - bValue
: bValue - aValue;
});
}
return sorted;
}, [products, sortConfig]);
return (
<div>
<button onClick={() => handleSort('price')}>
가격순 {sortConfig.key === 'price' && (
sortConfig.direction === 'asc' ? '▲' : '▼'
)}
</button>
<button onClick={() => handleSort('title')}>
이름순 {sortConfig.key === 'title' && (
sortConfig.direction === 'asc' ? '▲' : '▼'
)}
</button>
<ProductList products={sortedProducts} />
</div>
);
}
9. 실전 정렬 함수 모음
재사용 가능한 정렬 함수들입니다.
// 정렬 유틸리티 함수
const sortUtils = {
// 숫자 오름차순
numberAsc: (a, b, key) => a[key] - b[key],
// 숫자 내림차순
numberDesc: (a, b, key) => b[key] - a[key],
// 문자열 오름차순
stringAsc: (a, b, key) => a[key].localeCompare(b[key]),
// 문자열 내림차순
stringDesc: (a, b, key) => b[key].localeCompare(a[key]),
// 날짜 최신순
dateDesc: (a, b, key) => new Date(b[key]) - new Date(a[key]),
// 날짜 오래된순
dateAsc: (a, b, key) => new Date(a[key]) - new Date(b[key])
};
// 사용 예시
const sortedByPrice = [...products].sort((a, b) =>
sortUtils.numberAsc(a, b, 'price')
);
const sortedByName = [...products].sort((a, b) =>
sortUtils.stringAsc(a, b, 'name')
);
10. 필터링과 정렬 함께 사용하기
function FilterAndSort() {
const [products, setProducts] = useState([]);
const [category, setCategory] = useState('all');
const [sortOption, setSortOption] = useState('default');
const processedProducts = useMemo(() => {
// 1. 필터링
let filtered = products;
if (category !== 'all') {
filtered = products.filter(p => p.category === category);
}
// 2. 정렬
const sorted = [...filtered];
switch (sortOption) {
case 'price-asc':
return sorted.sort((a, b) => a.price - b.price);
case 'price-desc':
return sorted.sort((a, b) => b.price - a.price);
default:
return sorted;
}
}, [products, category, sortOption]);
return (
<div>
{/* 카테고리 필터 */}
<select onChange={(e) => setCategory(e.target.value)}>
<option value="all">전체</option>
<option value="electronics">전자제품</option>
<option value="clothing">의류</option>
</select>
{/* 정렬 옵션 */}
<select onChange={(e) => setSortOption(e.target.value)}>
<option value="default">기본순</option>
<option value="price-asc">가격 낮은순</option>
<option value="price-desc">가격 높은순</option>
</select>
{/* 결과 */}
<div>총 {processedProducts.length}개의 상품</div>
<ProductList products={processedProducts} />
</div>
);
}
11. 실전 팁
1. 빈 배열 체크
if (!products || products.length === 0) {
return <div>상품이 없습니다</div>;
}
2. null/undefined 처리
const sorted = [...products].sort((a, b) => {
// price가 없는 상품은 맨 뒤로
if (!a.price) return 1;
if (!b.price) return -1;
return a.price - b.price;
});
3. 대소문자 구분 없이 정렬
const sorted = [...products].sort((a, b) =>
a.name.toLowerCase().localeCompare(b.name.toLowerCase())
);
4. 안정적인 정렬 (원본 순서 유지)
// 같은 값일 때 원본 순서 유지
const sorted = [...products].sort((a, b) => {
const priceCompare = a.price - b.price;
if (priceCompare !== 0) return priceCompare;
// 가격이 같으면 원본 인덱스 순서 유지
return products.indexOf(a) - products.indexOf(b);
});
마무리
정렬 기능 구현에 필요한 핵심 JavaScript 문법을 정리하면:
- sort(): 배열 정렬의 기본 메서드
- 비교 함수: (a, b) => a - b 패턴 이해하기
- localeCompare(): 문자열 자연스러운 정렬
- 스프레드 연산자: 원본 배열 보존
- useMemo: 성능 최적화
- 다중 조건 정렬: 우선순위 정렬 구현
이러한 개념들을 활용하면 사용자 친화적인 정렬 기능을 자유롭게 구현할 수 있습니다!
더 자세한 내용이 궁금하시다면?
정렬부터 고급 필터링, 검색 기능까지! 실무에서 바로 사용할 수 있는 쇼핑몰 구축 노하우가 궁금하시다면 인프런 강의를 확인해주세요!
'Youtube 동영상 > javascript & jQuery' 카테고리의 다른 글
| 페이지네이션 구현을 위한 JavaScript 핵심 문법 (0) | 2025.12.18 |
|---|---|
| Fetch API로 상품 데이터 조회하고 화면에 출력하기 (0) | 2025.12.18 |
| Glassmorphism Generator - 블러 필터 생성기 javascript로 구현하기 #글래스모피즘 (0) | 2025.07.04 |
| Hangman React 프로젝트 생성 가이드: 유튜브 영상과 함께하는 튜토리얼 (1) | 2024.11.18 |
| javascript Typing Effect - 자바스크립트 타이핑 효과 구현하기 (1) | 2024.09.10 |