From 84113a8c48d1ead5b00d921e971a6433bf85b39e Mon Sep 17 00:00:00 2001 From: caadiq Date: Wed, 21 Jan 2026 14:26:59 +0900 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=EC=9D=BC=EC=A0=95=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80/=EC=88=98=EC=A0=95=20=ED=8E=98=EC=9D=B4=EC=A7=80=20us?= =?UTF-8?q?eEffect=20=E2=86=92=20useQuery=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - React 18 Strict Mode 중복 요청 방지 - members, categories를 useQuery로 전환 - 수정 모드 일정 로드는 useEffect 유지 (폼 상태 초기화 필요) Co-Authored-By: Claude Opus 4.5 --- .../src/pages/pc/admin/AdminScheduleForm.jsx | 57 ++++++++----------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/frontend/src/pages/pc/admin/AdminScheduleForm.jsx b/frontend/src/pages/pc/admin/AdminScheduleForm.jsx index b4b3642..d4ef8f2 100644 --- a/frontend/src/pages/pc/admin/AdminScheduleForm.jsx +++ b/frontend/src/pages/pc/admin/AdminScheduleForm.jsx @@ -1,5 +1,6 @@ import { useState, useEffect, useRef } from "react"; import { useNavigate, Link, useParams } from "react-router-dom"; +import { useQuery } from "@tanstack/react-query"; import { motion, AnimatePresence } from "framer-motion"; import { formatDate } from "../../../utils/date"; import { @@ -42,7 +43,6 @@ function AdminScheduleForm() { const { toast, setToast } = useToast(); const [loading, setLoading] = useState(false); - const [members, setMembers] = useState([]); // 폼 데이터 (날짜/시간 범위 지원) const [formData, setFormData] = useState({ @@ -77,8 +77,22 @@ function AdminScheduleForm() { const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [deleteTargetIndex, setDeleteTargetIndex] = useState(null); - // 카테고리 목록 (API에서 로드) - const [categories, setCategories] = useState([]); + // 멤버 목록 조회 + const { data: membersData = [] } = useQuery({ + queryKey: ["members"], + queryFn: getMembers, + enabled: isAuthenticated, + staleTime: 5 * 60 * 1000, + }); + const members = membersData.filter((m) => !m.is_former); + + // 카테고리 목록 조회 + const { data: categories = [] } = useQuery({ + queryKey: ["admin", "categories"], + queryFn: categoriesApi.getCategories, + enabled: isAuthenticated, + staleTime: 5 * 60 * 1000, + }); // 저장 중 상태 const [saving, setSaving] = useState(false); @@ -132,28 +146,16 @@ function AdminScheduleForm() { return days[date.getDay()]; }; - // 카테고리 로드 - const fetchCategories = async () => { - try { - const data = await categoriesApi.getCategories(); - setCategories(data); - // 첫 번째 카테고리를 기본값으로 설정 - if (data.length > 0 && !formData.category) { - setFormData((prev) => ({ ...prev, category: data[0].id })); - } - } catch (error) { - console.error("카테고리 로드 오류:", error); - } - }; - + // 첫 번째 카테고리를 기본값으로 설정 useEffect(() => { - if (!isAuthenticated) return; + if (categories.length > 0 && !formData.category && !isEditMode) { + setFormData((prev) => ({ ...prev, category: categories[0].id })); + } + }, [categories, isEditMode]); - fetchMembers(); - fetchCategories(); - - // 수정 모드일 경우 기존 데이터 로드 - if (isEditMode && id) { + // 수정 모드일 경우 기존 데이터 로드 + useEffect(() => { + if (isAuthenticated && isEditMode && id) { fetchSchedule(); } }, [isAuthenticated, isEditMode, id]); @@ -223,15 +225,6 @@ function AdminScheduleForm() { } }; - const fetchMembers = async () => { - try { - const data = await getMembers(); - setMembers(data.filter((m) => !m.is_former)); - } catch (error) { - console.error("멤버 로드 오류:", error); - } - }; - // 멤버 토글 const toggleMember = (memberId) => { const newMembers = formData.members.includes(memberId)