- Redux의 Action과 Reducer 사이에서 추가적인 작업을 수행할 수 있는 코드를 의미합니다. 미들웨어는 주로 비동기 작업, 로깅, 오류 처리등을 수행하는 데 사용됩니다.
💡 [참고] Redux Tookit 종류
종류
설명
redux-thunk
비동기 작업을 처리하기 위한 함수를 반환하는 미들웨어
redux-saga
제너레이터 함수를 사용하여 비동기 작업을 처리하는 미들웨어
redux-observable
RxJS를 사용하여 비동기 작업을 처리하는 미들웨어
redux-promise-middleware
Promise를 사용하여 비동기 작업을 처리하는 미들웨어
redux-logger
액션을 콘솔에 출력해주는 미들웨어
redux-flipper
React Native 앱의 Redux 스토어를 모니터링하고, 디버깅하는 데 사용되는 디버깅 도구
redux-immutableCheck
불변성을 체크하는 미들웨어
redux-serializableCheck
액션 객체가 직렬화 가능한지 체크하는 미들웨어
middleware1
사용자가 만든 미들웨어
middleware2
사용자가 만든 미들웨어
4) Redux Tookit(RTK) 구성하기
1. 라이브러리를 설치합니다
# 1.redux를 구성하기 위한 라이브러리(npm)
$ npm i react-redux @reduxjs/toolkit
# or
# 1.redux를 구성하기 위한 라이브러리(yarn)
$ yarn add react-redux @reduxjs/toolkit
# 2. redux의 값을 유지하기 위한 라이브러리(npm)
$ npm i @react-native-async-storage/async-storage redux-persist && npm i -save--dev @types/redux-persist
# or
# 2. redux의 값을 유지하기 위한 라이브러리(yarn)
$ yarn add @react-native-async-storage/async-storage && yarn add --dev @types/redux-persist
# 3. redux를 디버깅 하기 위한 라이브러리(npm)
$ npm i redux-logger && npm i --save-dev redux-logger
# or
# 3. redux를 디버깅 하기 위한 라이브러리(yarn)
$ yarn add redux-logger && yarn add --dev redux-logger
- Redux Toolkit에서 상태 관리를 단순화하고 구조화하기 위해 도입된 개념입니다. - Slice는 액션과 리듀서를 한 곳에 모아 두고, 상태의 특정 부분을 관리할 수 있게 해 줍니다. - 일반적으로 Redux Toolkit의 createSlice 함수를 사용하여 생성됩니다.
💡Slice 구성 및 설정 과정 -1
- reducer를 작성하는 유틸리티 메서드입니다. 초기 상태 및 reducer 함수를 정의하고, 액션 생성 함수를 자동으로 생성합니다.
1. TemplateUserSlice에서 관리하는 상태값(State)을 정의합니다.
2. TemplateUserSlice에서 관리하는 Reducer 메서드를 관리합니다.
3. Reducer 메서드를 정의하여 외부에서 Redux의 상태를 변경할 수 있도록 구성합니다.
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { TemplateType } from "types/template/TemplateType";
/**
* UserSlice의 관리하는 상태값(State)을 정의합니다.
*/
const initialState = {
name: '',
nickName: '',
email: '',
accessToken: '',
};
/**
* TemplateUserSlice에서 관리하는 Reducer 메서드를 관리합니다.
*/
const TemplateUserSlice = createSlice({
name: 'templateUser',
initialState,
reducers: {
// 모든 사용자 정보를 상태에 저장합니다.
setUser(state, action) {
state.name = action.payload.name;
state.nickName = action.payload.nickName;
state.email = action.payload.email;
state.accessToken = action.payload.accessToken;
},
// 사용자 이름을 상태에 저장합니다.
setName(state, action) {
state.name = action.payload;
},
// 닉네임을 상태에 저장합니다.
setNickName(state, action) {
state.nickName = action.payload;
},
// 사용자 이메일을 상태에 저장합니다.
setEmail(state, action) {
state.email = action.payload;
},
// 접근 토큰을 상태에 저장합니다.
setAccessToken(state, action) {
state.accessToken = action.payload;
},
},
});
/**
* Reducer 메서드를 정의하여 외부에서 Redux의 상태를 변경할 수 있도록 구성합니다.
*/
export const { setUser, setName, setNickName, setEmail, setAccessToken } = TemplateUserSlice.actions
export default TemplateUserSlice.reducer
4. Slice 구성 및 설정 과정-2
💡 Slice 구성 및 설정 과정 -2
- 동일하게 reducer를 작성하는 유틸리티 메서드입니다. 초기 상태 및 reducer 함수를 정의하고, 액션 생성 함수를 자동으로 생성합니다.
1. TemplateSlice에서 관리하는 상태값(State)을 정의합니다.
2. TemplateSlice에서 관리하는 Reducer 메서드를 관리합니다.
3. Reducer 메서드를 정의하여 외부에서 Redux의 상태를 변경할 수 있도록 구성합니다.
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
/**
* TemplateSlice에서 관리하는 상태값(State)을 정의합니다.
*/
const initialState = {
tempId: '',
tempName: '',
tempMenu: '',
};
/**
* TemplateSlice에서 관리하는 Reducer 메서드를 관리합니다.
*/
const TemplateSlice = createSlice({
name: 'template',
initialState,
reducers: {
// 모든 사용자 정보를 상태에 저장합니다.
setTemplate(state, action) {
state.tempId = action.payload.tempId;
state.tempName = action.payload.tempName;
state.tempMenu = action.payload.tempMenu;
},
setTempId(state, action) {
state.tempId = action.payload;
},
setTempName(state, action) {
state.tempName = action.payload;
},
setTempMenu(state, action) {
state.tempMenu = action.payload;
},
},
});
/**
* Reducer 메서드를 정의하여 외부에서 Redux의 상태를 변경할 수 있도록 구성합니다.
*/
export const { setTemplate, setTempId, setTempName, setTempMenu } = TemplateSlice.actions
export default TemplateSlice.reducer
5. RootReducer 구성 및 설정
💡 RootReducer
- Redux에서 사용하는 하나의 최상위 리듀서(Reducer)입니다. 애플리케이션의 상태를 관리하기 위해 여러 개의 리듀서를 하나로 결합하여 사용하는데, 이 결합된 리듀서(combineReducers)를 Root Reducer라고 합니다. - 각 리듀서는 상태의 특정 부분을 담당하며, Root Reducer는 이들을 하나로 합쳐 전체 상태 트리를 관리합니다.
💡 RootReducer 구성 및 설정
- 사용 목적에 따라서 Slice 단위로 분리하여서 Root Reducer를 구성합니다.
import { combineReducers } from "@reduxjs/toolkit";
import templateSlice from "./slice/TemplateSlice";
import templateUserSlice from "./slice/TemplateUserSlice";
/**
* 사용 목적에 따라서 Slice 단위로 분리하여서 Root Reducer를 구성합니다.
*/
const RootReducer = combineReducers({
templateUser: templateUserSlice,
template: templateSlice
});
export type RootState = ReturnType<typeof RootReducer>;
export default RootReducer;
6. Redux Store 구성 및 설정
💡 Redux Store
- 애플리케이션의 상태를 보관하는 중앙 저장소입니다. Redux는 단일 상태 트리 구조를 가지고 있기 때문에, 애플리케이션의 모든 상태는 하나의 store 객체 안에 저장됩니다. - 이 store는 애플리케이션의 상태를 읽고, 변경하고, 구독할 수 있는 여러 기능을 제공합니다.
💡 Redux Store 구성 및 설정
1. Redux-Persist 설정 값을 구성합니다
- redux의 값이 유지되는 redux-persist를 통해서 각각의 설정을 구성합니다. - storage 속성을 통해서 React-native의 내부저장소인 react-native-async-store 내에 이를 저장하여 값을 유지합니다.
2. 애플리케이션의 '상태'를 관리하기 위한 Store 구성합니다.
- 구성한 redux-persist에서 설정한 값과 Root Reducer에서 지정한 값을 기반으로 reducer를 지정하고 미들웨어를 지정합니다.
3. 외부에서 사용할 수 있도록 Persistor를 구성합니다.
import { configureStore } from "@reduxjs/toolkit";
import RootReducer, { RootState } from "./RootReducer";
import { persistStore, persistReducer, PersistConfig } from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
import logger from 'redux-logger'
/**
* 1. Redux-Persist에 설정 값을 구성합니다.
*/
const persistConfig: PersistConfig<RootState> = {
key: 'root', // 저장되는 값에 대한 식별자로 반드시 입력해주세요.
storage: AsyncStorage, // Redux가 저장되는 Storage로 AsyncStorage를 이용합니다.
blacklist: [], // 선택적으로 저장하지 않을 리듀서를 지정할 수 있습니다.
};
/**
* 2. 애플리케이션의 '상태'를 관리하기 위한 Store 구성합니다.
*/
export const Store = configureStore({
// Redux-Persist 설정값과 구성한 RootReducer를 통해 Reducer를 구성합니다.
reducer: persistReducer(persistConfig, RootReducer)!,
// 미들 웨어로 logger를 사용합니다.
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger),
// middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: false }),
});
/**
* 3. 외부에서 사용할 수 있도록 persistor를 구성합니다.
*/
export const Persistor = persistStore(Store);
export type AppDispatch = typeof Store.dispatch
import { useDispatch, useSelector } from "react-redux";
import { setEmail } from "modules/redux/slice/TemplateUserSlice";
const TemplateReduxScreen = ({ route, navigation, appState }: CommonType.CommonProps) => {
const dispatch = useDispatch()
/**
* Redux 공간에 사용자 정보를 세팅합니다.
*/
const setUserInfo = () => {
const result = dispatch(setEmail("hohoho"))
console.log("result :: ", result)
}
}
2. 현재 상태 불러오기
💡 현재 상태 불러오기
- useSelector() 함수를 통해서 Redux 저장소를 확인하여서 현재 상태를 불러옵니다.
import { RootState } from "modules/redux/RootReducer";
import { useDispatch, useSelector } from "react-redux";
const TemplateReduxScreen = ({ route, navigation, appState }: CommonType.CommonProps) => {
const dispatch = useDispatch()
// Redux 저장소에서 데이터를 조회해옵니다.
const userInfo = useSelector((state: RootState) => state.templateUser);
/**
* Redux 상태에 사용자 정보를 가져옵니다.
*/
const selectUserInfo = () => {
console.log("userInfo :: ", userInfo);
}
}
99) 참고
1. Redux를 변경하였는데 초기값이 변경되지 않습니다.
💡 Redux를 변경하였는데 초기값이 변경되지 않습니다.
- Redux는 기본적으로 디바이스의 메모리에 저장이 됩니다. - Redux의 구조가 변경된 경우, 메모리 데이터를 지워주는 것이 적절합니다. - Redux는 상태 관리를 위해 메모리에 데이터를 저장하므로 구조 변경 시 이전 데이터가 남아있을 수 있습니다. 따라서 변경된 Redux 구조에 맞게 메모리 데이터를 지워주는 것이 좋습니다.