본문 바로가기
프로젝트/웹

[React] 관리자단 슬라이스 : 한국어 교육 웹 서비스 '재밌는한국어' 프로젝트

by AI읽어주는남자 2025. 10. 16.
반응형

3. 전역 상태 관리 분석: adminSlice.jsx

이 파일은 Redux Toolkit의 createSlice 기능을 사용하여 관리자 페이지에서 공통으로 사용되는 모든 데이터를 관리합니다. 이를 '전역 상태 관리'라고 하며, 여러 컴포넌트가 동일한 데이터에 접근하고 수정할 수 있게 해줍니다.

3.1. 코드 전문 (주석 포함)

// Redux Toolkit에서 createSlice 함수를 가져옵니다.
// createSlice는 리듀서와 액션을 한 번에 만드는 편리한 함수입니다.
import { createSlice } from "@reduxjs/toolkit";

// [1] 이 슬라이스(slice)에서 관리할 상태의 초기값을 정의합니다.
// 앱이 처음 시작될 때 이 값들로 상태가 채워집니다.
const initialState = {
    genres: [],         // 장르 목록을 저장할 배열
    studies: [],        // 교육(주제) 목록을 저장할 배열
    exams: [],          // 예문 목록을 저장할 배열
    audios: [],         // 음성 파일 목록을 저장할 배열
    currentStudy: null, // 현재 보고 있거나 수정 중인 단일 교육 정보
    currentExam: null,  // 현재 보고 있거나 수정 중인 단일 예문 정보
    loading: false,     // API 요청 등 비동기 작업이 진행 중인지 여부 (예: 로딩 스피너 표시용)
    error: null         // 에러가 발생했을 때 에러 메시지를 저장
};

// [2] 'admin'이라는 이름의 슬라이스를 생성합니다.
const adminSlice = createSlice({
    name: "admin",      // 슬라이스의 이름. 이 이름은 액션 타입 생성 시 접두사로 사용됩니다. (예: 'admin/setGenres')
    initialState,      // 위에서 정의한 초기 상태

    // reducers: 상태(state)를 어떻게 변경할지에 대한 로직을 담고 있는 함수들의 모음입니다.
    reducers: {
        // 각 리듀서 함수는 두 개의 인자를 받습니다: state와 action
        // state: 현재의 상태 값 (Redux Toolkit이 내부적으로 불변성을 관리해줘서 직접 수정하는 것처럼 코딩 가능)
        // action: 컴포넌트에서 보낸 요청 정보. action.payload에 전달된 데이터가 담겨 있습니다.

        // --- 상태 설정(Set) 리듀서들 --- 
        // API를 통해 받아온 전체 데이터를 스토어에 저장합니다.
        setGenres: (state, action) => { state.genres = action.payload; },
        setStudies: (state, action) => { state.studies = action.payload; },
        setExams: (state, action) => { state.exams = action.payload; },
        setAudios: (state, action) => { state.audios = action.payload; },
        setCurrentStudy: (state, action) => { state.currentStudy = action.payload; },
        setCurrentExam: (state, action) => { state.currentExam = action.payload; },
        setLoading: (state, action) => { state.loading = action.payload; },
        setError: (state, action) => { state.error = action.payload; },

        // --- 개별 데이터 추가/수정/삭제 리듀서들 --- 
        // (현재 프로젝트에서는 API 호출 후 전체 목록을 다시 불러오는 방식을 사용하므로, 아래 리듀서들은 직접 사용되지 않을 수 있습니다.)
        // (하지만, 이런 방식도 가능하다는 것을 보여주는 좋은 예시입니다.)

        // 새 데이터를 기존 배열에 추가
        addGenre: (state, action) => { state.genres.push(action.payload); },
        addStudy: (state, action) => { state.studies.push(action.payload); },
        addExam: (state, action) => { state.exams.push(action.payload); },
        addAudio: (state, action) => { state.audios.push(action.payload); },

        // 특정 데이터를 수정
        updateStudy: (state, action) => {
            // studies 배열에서 수정할 항목의 인덱스를 찾습니다. (id가 일치하는 항목)
            const index = state.studies.findIndex(s => s.studyNo == action.payload.studyNo);
            // 인덱스를 찾았다면, 해당 위치의 데이터를 action.payload로 교체합니다.
            if (index !== -1) { state.studies[index] = action.payload; }
        },

        // 특정 데이터를 삭제
        deleteStudy: (state, action) => {
            // action.payload로 전달된 studyNo와 일치하지 않는 항목들만 남겨서 새로운 배열을 만듭니다.
            state.studies = state.studies.filter(s => s.studyNo !== action.payload);
        },
        deleteExam: (state, action) => {
            state.exams = state.exams.filter(e => e.examNo !== action.payload);
        },
        deleteAudio: (state, action) => {
            state.audios = state.audios.filter(a => a.audioNo !== action.payload);
        },
    },
});

// [3] 생성된 액션 생성자(Action Creators)들을 export 합니다.
// 컴포넌트에서 `dispatch(setGenres(data))` 와 같이 사용할 수 있게 됩니다.
export const {
    setGenres,
    setStudies,
    setExams,
    setAudios,
    setCurrentStudy,
    setCurrentExam,
    setLoading,
    setError,
    addGenre,
    addStudy,
    addExam,
    addAudio,
    updateStudy,
    deleteStudy,

} = adminSlice.actions;

// [4] 슬라이스의 리듀서를 export 합니다.
// 이 리듀서는 Redux 스토어 설정 파일(보통 store.js)에서 사용됩니다.
export default adminSlice.reducer;

3.2. 핵심 분석

  1. createSlice의 역할: Redux의 3가지 주요 요소인 액션(Actions), 리듀서(Reducers), 상태(State)를 하나의 객체 안에서 모두 정의하게 해주는 강력한 도구입니다. createSlice 덕분에 Redux 설정이 매우 간결해졌습니다.
  2. initialState: 이 슬라이스가 관리하는 모든 데이터의 '청사진' 또는 '초기 상태'입니다. 앱이 로드될 때 Redux 스토어는 이 initialState를 기반으로 admin 상태를 구성합니다.
  3. reducers 객체: 이 객체 안에 있는 함수들이 실제로 상태를 변경하는 로직을 담고 있습니다.
    • 예를 들어 setGenres: (state, action) => { state.genres = action.payload; } 라는 리듀서는, setGenres라는 액션이 실행될 때 state.genres의 값을 action.payload(컴포넌트에서 전달한 새로운 장르 목록 데이터)로 교체하라는 의미입니다.
    • Immer 라이브러리: Redux Toolkit은 내부적으로 Immer라는 라이브러리를 사용합니다. 덕분에 state.genres = ...state.genres.push(...) 처럼 상태를 직접 수정하는 것처럼 보이는 코드를 작성해도, 실제로는 불변성을 유지하며 안전하게 상태가 업데이트됩니다. (전통적인 Redux에서는 return { ...state, genres: action.payload } 와 같이 복잡하게 작성해야 했습니다.)
  4. export의 두 종류:
    • export const { ... } = adminSlice.actions;: 컴포넌트에서 상태 변경을 "요청"할 때 사용하는 액션 생성자 함수들을 내보냅니다. dispatch(setGenres(genresData))와 같이 사용됩니다.
    • export default adminSlice.reducer;: createSlice가 생성한 리듀서 로직 전체를 내보냅니다. 이 리듀서는 스토어를 설정하는 파일(store.js 등)에서 애플리케이션의 전체 리듀서에 통합됩니다.
반응형