From dac2234a0b58846a1085471999bcbfdb7d35fcab Mon Sep 17 00:00:00 2001 From: caadiq Date: Tue, 6 Jan 2026 12:26:40 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9D=BC=EC=A0=95=20=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EA=B4=80=EB=A6=AC=EB=A5=BC=20Zustand?= =?UTF-8?q?=EB=A1=9C=20=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - zustand 패키지 설치 - useScheduleStore 스토어 생성 - sessionStorage 관련 모든 복잡한 로직 제거 - 메모리 기반이라 SPA 내 이동 시 유지, 새로고침 시 자동 초기화 --- frontend/package-lock.json | 32 +++++++- frontend/package.json | 3 +- frontend/src/pages/pc/admin/AdminSchedule.jsx | 82 ++++++------------- frontend/src/stores/useScheduleStore.js | 36 ++++++++ 4 files changed, 92 insertions(+), 61 deletions(-) create mode 100644 frontend/src/stores/useScheduleStore.js diff --git a/frontend/package-lock.json b/frontend/package-lock.json index deeef76..58c99df 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,7 +17,8 @@ "react-ios-time-picker": "^0.2.2", "react-photo-album": "^3.4.0", "react-router-dom": "^6.22.3", - "react-window": "^2.2.3" + "react-window": "^2.2.3", + "zustand": "^5.0.9" }, "devDependencies": { "@types/react": "^18.3.3", @@ -2826,6 +2827,35 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" + }, + "node_modules/zustand": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.9.tgz", + "integrity": "sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/frontend/package.json b/frontend/package.json index ee51484..843e9b9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,7 +18,8 @@ "react-ios-time-picker": "^0.2.2", "react-photo-album": "^3.4.0", "react-router-dom": "^6.22.3", - "react-window": "^2.2.3" + "react-window": "^2.2.3", + "zustand": "^5.0.9" }, "devDependencies": { "@types/react": "^18.3.3", diff --git a/frontend/src/pages/pc/admin/AdminSchedule.jsx b/frontend/src/pages/pc/admin/AdminSchedule.jsx index 820f6b9..0c11925 100644 --- a/frontend/src/pages/pc/admin/AdminSchedule.jsx +++ b/frontend/src/pages/pc/admin/AdminSchedule.jsx @@ -8,6 +8,7 @@ import { import Toast from '../../../components/Toast'; import Tooltip from '../../../components/Tooltip'; +import useScheduleStore from '../../../stores/useScheduleStore'; function AdminSchedule() { const navigate = useNavigate(); @@ -20,47 +21,30 @@ function AdminSchedule() { return kstDate.toISOString().split('T')[0]; }; - // sessionStorage에서 저장된 상태 복원 (한 번만 실행) - // 일정 폼에서 돌아올 때만 복원 (fromScheduleForm 플래그 확인) - const stateRestoredRef = useRef(false); - const getStoredState = () => { - // 이미 복원 로직이 실행된 경우 다시 실행하지 않음 (StrictMode 이중 마운트 대응) - if (stateRestoredRef.current) { - const stored = sessionStorage.getItem('adminScheduleState'); - return stored ? JSON.parse(stored) : null; - } - stateRestoredRef.current = true; - - try { - const fromForm = sessionStorage.getItem('fromScheduleForm'); - if (fromForm) { - // 플래그 제거 후 상태 복원 - sessionStorage.removeItem('fromScheduleForm'); - const stored = sessionStorage.getItem('adminScheduleState'); - return stored ? JSON.parse(stored) : null; - } - // 폼에서 돌아온 게 아니면 상태 초기화 - sessionStorage.removeItem('adminScheduleState'); - return null; - } catch { return null; } - }; - const storedState = getStoredState(); - - + // Zustand 스토어에서 상태 가져오기 + const { + searchInput, setSearchInput, + searchTerm, setSearchTerm, + isSearchMode, setIsSearchMode, + selectedCategories, setSelectedCategories, + selectedDate, setSelectedDate, + currentDate, setCurrentDate, + } = useScheduleStore(); + // 로컬 상태 (페이지 이동 시 유지할 필요 없는 것들) const [loading, setLoading] = useState(false); const [user, setUser] = useState(null); const [toast, setToast] = useState(null); - const [searchInput, setSearchInput] = useState(storedState?.searchInput || ''); - const [searchTerm, setSearchTerm] = useState(storedState?.searchTerm || ''); - const [isSearchMode, setIsSearchMode] = useState(storedState?.isSearchMode || false); const [searchResults, setSearchResults] = useState([]); const [searchLoading, setSearchLoading] = useState(false); - const [selectedCategories, setSelectedCategories] = useState(storedState?.selectedCategories || []); - const [selectedDate, setSelectedDate] = useState(storedState?.selectedDate || getTodayKST()); - const [currentDate, setCurrentDate] = useState( - storedState?.currentDate ? new Date(storedState.currentDate) : new Date() - ); + + // selectedDate가 없으면 오늘 날짜로 초기화 + useEffect(() => { + if (!selectedDate) { + setSelectedDate(getTodayKST()); + } + }, []); + const [slideDirection, setSlideDirection] = useState(0); @@ -197,18 +181,7 @@ function AdminSchedule() { fetchSchedules(); }, [year, month]); - // 상태를 sessionStorage에 저장 (페이지 이동 시 복원용) - useEffect(() => { - const stateToSave = { - searchInput, - searchTerm, - isSearchMode, - selectedCategories, - selectedDate, - currentDate: currentDate.toISOString(), - }; - sessionStorage.setItem('adminScheduleState', JSON.stringify(stateToSave)); - }, [searchInput, searchTerm, isSearchMode, selectedCategories, selectedDate, currentDate]); + // 검색 모드로 돌아왔을 때 검색 결과 다시 로드 useEffect(() => { @@ -526,20 +499,14 @@ function AdminSchedule() {