오랜만의 블로그 글 작성이다.
취업은 여전히 어렵지만, 나는 키보드워리어 포기하지 않는다.
오늘은 Redux 사용법 중 환경을 구성하는 방법을 정리하도록 하고, 로그인 등의 로직 설계는 다음 글에서 정리하도록 하겠다.
redux는 클라이언트에서 전역 상태를 관리하기 위해 사용되는 라이브러리로 props drilling 없이 필요한 상태값을 불러올 수 있는 도구이다.
우리는 redux에서 권장하는 @reduxjs/toolkit의 다양한 함수를 사용하여 전역 상태 관리 환경을 구성 할 예정이다.
slice란? Redux Toolkit에서 제공하는 개념으로, 특정 상태와 그에 관련된 액션 및 리듀서들을 하나로 묶은 것입니다. 각각의 슬라이스는 Redux 상태의 한 부분을 관리하며, Redux Toolkit의 createSlice 함수로 생성할 수 있습니다.
createSlice 함수로 slice를 생성하면 slice가 정의된 action에 따라 reducer(함수)를 실행하여 전역 상태 한가지를 제어한다고 생각하면 편할 듯 하다.
import {createSlice} from '@reduxjs/toolkit';
// 초기 상태값읠 정의
const initialSlice = {
userData : {
name : '',
id : '',
role : 0,
},
isAuth : false,
isLoading : false,
error : ''
}
const userSlice = createSlice({
name : 'user',
initialState,
reducers : {},
extraReducers : (builder)=>{
// builder 객체의 addCase메서드를 사용하여 비동기 로직을 정의한다.
// ex) builder.addCase(비동기함수명.동작의상태 , (state, action)=>{
// 실행 할 로직을 작성
// })
}
});
// slice의 reducer들을 모두 export 하여 다른 스크립트에서 사용한다!
export default userSlice.reducer;
store란? : 전체 전역 상태를 보관하는 객체로, Redux 상태 관리의 핵심 역할을 합니다. 모든 상태, 액션, 리듀서가 스토어와 연결되어 있으며, React 컴포넌트는 스토어를 통해 상태를 조회하거나 액션을 디스패치하여 상태를 변경합니다.
말 그대로 전역 상태를 저장하는 저장소라고 생각하면 좋을 듯하다
// 예시
import combineReducer from '@reduxjs/toolkit';
import userReducer from '../slices/userSlice.js';
const combinedReducer = combineReducer({ user : userReducer });
// 예시
import {persistReducer} from 'redux-persist';
import {storage} from 'redux-persist/lib/storage';
// persistReducer 함수에 할당하기 위한 선언
const persistConfig = {
// 키 : 값
// storage or cookie
key : 'root-underdog',
storage
};
//
const persistedReducer = persistReducer(persistConfig, rootReducer);
// 예시
import {configuerStore} from '@reduxjs/toolkit';
import {FLUSH, PAUSE, PERSIST, PURGE, REGISTER, REHYDRATE, persistStore} from 'redux-persist';
// 스토어 생성
export const store = configureStore({
reducer : persistedReducer,
middleware : (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck : {
ignoreActions : [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
}
})
});
// 스토어를 영구화
export const persistor = persistStore(store);
- provider란? : 전역 공간을 적용하는 일종의 context와 같은 것으로 index.js에 하위 요소를 감싼다. PersistGate를 자식 요소로 둔다.
- PersistGate란? : Redux 스토어의 상태를 로컬 스토리지(localStorage, sessionStorage 등)에 저장하여, 브라우저 새로고침이나 페이지 이동 시에도 상태가 유지되도록 한다.
!!! PersistGate를 Provider로 감싸야 하는 이유 !!!
PersistGate의 동작 방식: PersistGate는 스토어에서 데이터를 불러오는 작업이 완료될 때까지 컴포넌트 렌더링을 지연시킵니다. 즉, PersistGate 안에 있는 모든 컴포넌트는 데이터가 준비될 때까지 렌더링되지 않습니다.
Provider의 역할: Provider는 스토어를 제공하는 역할만 합니다. 스토어의 데이터가 언제 준비되는지에 대한 제어는 하지 않습니다.
위치에 따른 차이:
PersistGate를 Provider 바깥에 감싸면: 모든 컴포넌트가 데이터가 준비되기 전에 렌더링될 수 있습니다. 이는 데이터가 아직 없음에도 불구하고 UI가 렌더링되어 버리는 문제를 야기할 수 있습니다.
PersistGate를 Provider 안쪽에 감싸면: PersistGate가 데이터를 불러오는 동안 컴포넌트 렌더링이 지연되어, 데이터가 준비된 후에야 UI가 렌더링됩니다.
// 예시
import {Provider} from 'react-redux';
import { persistor, store } from './store/store';
import { PersistGate } from 'redux-persist/integration/react';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>
</>
);
이렇게 redux 환경을 구성하는 방법을 정리했다. 다음 글에선 로그인 등의 로직을 적용하는 방법을 정리하도록 하겠다.