웹: AlbumDetail, AlbumGallery 페이지 useQuery로 리팩토링

This commit is contained in:
caadiq 2026-01-12 17:44:28 +09:00
parent 443bd203ca
commit dc65858d6b
4 changed files with 65 additions and 89 deletions

View file

@ -1,6 +1,7 @@
import { motion, AnimatePresence } from 'framer-motion';
import { useState, useEffect, useCallback, useRef } from 'react';
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import { Play, Calendar, Music2, Clock, X, Download, ChevronDown, ChevronUp, FileText, ChevronRight } from 'lucide-react';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Virtual } from 'swiper/modules';
@ -9,17 +10,21 @@ import { getAlbumByName } from '../../../api/public/albums';
import { formatDate } from '../../../utils/date';
import LightboxIndicator from '../../../components/common/LightboxIndicator';
//
function MobileAlbumDetail() {
const { name } = useParams();
const navigate = useNavigate();
const [album, setAlbum] = useState(null);
const [loading, setLoading] = useState(true);
const [lightbox, setLightbox] = useState({ open: false, images: [], index: 0, showNav: true });
const [showAllTracks, setShowAllTracks] = useState(false);
const [showDescriptionModal, setShowDescriptionModal] = useState(false);
const swiperRef = useRef(null);
// useQuery
const { data: album, isLoading: loading } = useQuery({
queryKey: ['album', name],
queryFn: () => getAlbumByName(name),
enabled: !!name,
});
// -
const openLightbox = useCallback((images, index, options = {}) => {
setLightbox({ open: true, images, index, showNav: options.showNav !== false, teasers: options.teasers });
@ -85,18 +90,6 @@ function MobileAlbumDetail() {
return () => { document.body.style.overflow = ''; };
}, [lightbox.open, showDescriptionModal]);
useEffect(() => {
getAlbumByName(name)
.then(data => {
setAlbum(data);
setLoading(false);
})
.catch(error => {
console.error('앨범 로드 오류:', error);
setLoading(false);
});
}, [name]);
//
const getTotalDuration = () => {
if (!album?.tracks) return '';

View file

@ -1,5 +1,6 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import { X, Download, ChevronRight, Info, Users, Tag } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { Swiper, SwiperSlide } from 'swiper/react';
@ -12,34 +13,29 @@ import LightboxIndicator from '../../../components/common/LightboxIndicator';
function MobileAlbumGallery() {
const { name } = useParams();
const navigate = useNavigate();
const [album, setAlbum] = useState(null);
const [photos, setPhotos] = useState([]);
const [loading, setLoading] = useState(true);
const [selectedIndex, setSelectedIndex] = useState(null);
const [showInfo, setShowInfo] = useState(false);
const swiperRef = useRef(null);
useEffect(() => {
getAlbumByName(name)
.then(data => {
setAlbum(data);
const allPhotos = [];
if (data.conceptPhotos && typeof data.conceptPhotos === 'object') {
Object.entries(data.conceptPhotos).forEach(([concept, photos]) => {
photos.forEach(p => allPhotos.push({
...p,
concept: concept !== 'Default' ? concept : null
}));
});
}
setPhotos(allPhotos);
setLoading(false);
})
.catch(error => {
console.error('앨범 데이터 로드 오류:', error);
setLoading(false);
});
}, [name]);
// useQuery
const { data: album, isLoading: loading } = useQuery({
queryKey: ['album', name],
queryFn: () => getAlbumByName(name),
enabled: !!name,
});
//
const photos = useMemo(() => {
if (!album?.conceptPhotos) return [];
const allPhotos = [];
Object.entries(album.conceptPhotos).forEach(([concept, conceptPhotos]) => {
conceptPhotos.forEach(p => allPhotos.push({
...p,
concept: concept !== 'Default' ? concept : null
}));
});
return allPhotos;
}, [album]);
// -
const openLightbox = useCallback((index) => {

View file

@ -1,5 +1,6 @@
import { useState, useEffect, useCallback, memo } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import { motion, AnimatePresence } from 'framer-motion';
import { Calendar, Music2, Clock, X, ChevronLeft, ChevronRight, Download, MoreVertical, FileText } from 'lucide-react';
import { getAlbumByName } from '../../../api/public/albums';
@ -9,15 +10,20 @@ import LightboxIndicator from '../../../components/common/LightboxIndicator';
function AlbumDetail() {
const { name } = useParams();
const navigate = useNavigate();
const [album, setAlbum] = useState(null);
const [loading, setLoading] = useState(true);
const [lightbox, setLightbox] = useState({ open: false, images: [], index: 0 });
const [slideDirection, setSlideDirection] = useState(0);
const [imageLoaded, setImageLoaded] = useState(false);
const [preloadedImages] = useState(() => new Set()); // URL
const [preloadedImages] = useState(() => new Set());
const [showDescriptionModal, setShowDescriptionModal] = useState(false);
const [showMenu, setShowMenu] = useState(false);
// useQuery
const { data: album, isLoading: loading } = useQuery({
queryKey: ['album', name],
queryFn: () => getAlbumByName(name),
enabled: !!name,
});
//
const goToPrev = useCallback(() => {
if (lightbox.images.length <= 1) return;
@ -125,18 +131,6 @@ function AlbumDetail() {
});
}, [lightbox.open, lightbox.index, lightbox.images, preloadedImages]);
useEffect(() => {
getAlbumByName(name)
.then(data => {
setAlbum(data);
setLoading(false);
})
.catch(error => {
console.error('앨범 데이터 로드 오류:', error);
setLoading(false);
});
}, [name]);
// URL - API
//

View file

@ -1,5 +1,6 @@
import { useState, useEffect, useCallback, memo } from 'react';
import { useState, useEffect, useCallback, memo, useMemo } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import { motion, AnimatePresence } from 'framer-motion';
import { X, ChevronLeft, ChevronRight, Download } from 'lucide-react';
import { RowsPhotoAlbum } from 'react-photo-album';
@ -40,42 +41,34 @@ const galleryStyles = `
function AlbumGallery() {
const { name } = useParams();
const navigate = useNavigate();
const [album, setAlbum] = useState(null);
const [photos, setPhotos] = useState([]);
const [loading, setLoading] = useState(true);
const [lightbox, setLightbox] = useState({ open: false, index: 0 });
const [imageLoaded, setImageLoaded] = useState(false);
const [slideDirection, setSlideDirection] = useState(0);
const [preloadedImages] = useState(() => new Set()); // URL
const [preloadedImages] = useState(() => new Set());
useEffect(() => {
getAlbumByName(name)
.then(data => {
setAlbum(data);
const allPhotos = [];
// useQuery
const { data: album, isLoading: loading } = useQuery({
queryKey: ['album', name],
queryFn: () => getAlbumByName(name),
enabled: !!name,
});
if (data.conceptPhotos && typeof data.conceptPhotos === 'object') {
Object.entries(data.conceptPhotos).forEach(([concept, photos]) => {
photos.forEach(p => allPhotos.push({
// API URL
mediumUrl: p.medium_url,
originalUrl: p.original_url,
width: p.width || 800,
height: p.height || 1200,
title: concept,
members: p.members ? p.members.split(', ') : []
}));
});
}
setPhotos(allPhotos);
setLoading(false);
})
.catch(error => {
console.error('앨범 데이터 로드 오류:', error);
setLoading(false);
});
}, [name]);
//
const photos = useMemo(() => {
if (!album?.conceptPhotos) return [];
const allPhotos = [];
Object.entries(album.conceptPhotos).forEach(([concept, conceptPhotos]) => {
conceptPhotos.forEach(p => allPhotos.push({
mediumUrl: p.medium_url,
originalUrl: p.original_url,
width: p.width || 800,
height: p.height || 1200,
title: concept,
members: p.members ? p.members.split(', ') : []
}));
});
return allPhotos;
}, [album]);
//
const openLightbox = (index) => {