React & React Native/라이브러리 활용
[RN] React Native Redux 이해하고 설정하기 : RTK(Redux Toolkit)
adjh54
2023. 6. 21. 20:33
반응형
해당 글에서는 React-native 개발 환경에서 상태관리를 위해 RTK(Redux ToolKit)에 대해 이해하고 환경설정 하는 방법에 대해서 공유합니다.
1) Redux ToolKit(RTK)
💡 Redux ToolKit
- Redux의 사용을 간편하게 하고, 코드의 복잡성을 줄이며, 일반적인 Redux 작업을 더 쉽게 하기 위해 만들어진 라이브러리입니다.
- 이는 Redux 애플리케이션을 구축하는 데 필요한 다양한 도구와 유틸리티를 제공합니다.
[ 더 알아보기 ]
💡Redux
- React.js 애플리케이션에서 사용되는 상태 관리 라이브러리입니다. Redux는 애플리케이션에서 발생하는 모든 데이터를 중앙에 저장하고 관리합니다. 이를 통해 애플리케이션의 상태를 예측 가능하고 디버깅이 용이하게 만들어줍니다.
1. Redux와 Redux Toolkit의 차이
💡 Redux와 Redux Toolkit의 차이
- 공식 사이트 내용을 확인해 보면 Redux의 세 가지 문제를 해결하기 위해 만들어져 있습니다.
- "Redux 스토어 구성이 너무 복잡합니다."
- "Redux가 유용한 작업을 수행하려면 많은 패키지를 추가해야 합니다."
- "Redux에는 너무 많은 상용구 코드가 필요합니다"
- Redux를 사용하면서 세 가지 요인으로 인해 Redux 사용에 대한 불편함을 가지고 이를 해결하기 위해서 Redux Toolkit을 사용합니다.
분류 | Redux | Redux ToolKit |
코드량 | 많은 코드 양 | 적은 코드 양 |
Immutable 추가 | Immutable 업데이트 미지원 | Immutable 업데이트 지원 |
createSlice 함수 추가 | 상태, 액션, 리듀서를 각각 개별적으로 작성 | createSlice 함수로 상태, 액션, 리듀서를 한 번에 생성 |
configureStore 함수 추가 | 스토어 생성 코드를 따로 작성 | configureStore 함수로 스토어 생성 코드 자동 생성 |
기본적인 미들웨어 포함 | 기본 미들웨어 미포함 | 몇 가지 기본 미들웨어 포함 |
2. Redux ToolKit(RTK) 주요 용어
용어 | 설명 |
Store | - 애플리케이션 ‘상태를 담고 있는 객체’를 의미합니다. - 상태를 변경하는 유일한 방법은 액션(Action)을 발생시킵니다. |
Action | - ‘상태의 변경’을 알리는 객체를 의미합니다. - type 프로퍼티를 가지고 있으며, 이 값을 통해 어떤 상태 변경을 하고자 하는지 구분 |
Reducer | - ’Action에 따라 상태를 업데이트’하는 함수를 의미합니다. |
Combine Reducer | - ‘Reducer 함수를 여러 개로 분리해서 관리’할 수 있도록 도와주는 함수를 의미합니다. |
Dispatch | - ‘Action을 발생시키는 함수’를 의미합니다. |
Middleware | - ‘Action’과 ‘Reducer’ 사이에서 추가적인 작업을 수행할 수 있는 코드를 의미합니다. |
3. Redux Toolkit(RTK) 주요 메서드
메서드 | 설명 |
configureStore() | Redux Store를 구성하는 메서드로, reducer 및 middleware를 설정하고 store를 반환합니다. |
createReducer() | 일반적인 reducer 함수를 작성하는 데 사용할 수 있는 유틸리티입니다. |
createAction() | 일반적인 액션 생성 함수를 작성하는 데 사용할 수 있는 유틸리티입니다. |
createSlice() | Redux Toolkit에서 reducer를 작성하는 유틸리티 메서드입니다. 초기 상태 및 reducer 함수를 정의하고, 액션 생성 함수를 자동으로 생성합니다. |
createAsyncThunk() | 비동기 작업을 수행하는 Action Creator를 생성하는 유틸리티 메서드입니다. |
createEntityAdapter() | 비정규화된 엔티티 데이터를 쉽게 관리할 수 있는 메서드입니다. |
createSelector() | Reselect 라이브러리와 함께 사용하여 성능 최적화된 셀렉터를 생성할 수 있습니다. |
useSelector() | Redux store에서 state를 가져오는 Hook입니다. 이 Hook은 컴포넌트 내에서 Redux store의 state를 불러와 사용할 수 있습니다. |
useDispatch() | Redux store에서 action을 dispatch하는 Hook입니다. 이 Hook을 이용하면 컴포넌트에서 Redux store의 state를 변경할 수 있습니다. |
3) Redux Toolkit Middleware
💡 Redux Toolkit Middleware
- 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
2. 프로젝트 디렉터리 구성
3. Slice 구성 및 설정 과정 -1
💡Slice
- 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
7. Provider 구성 및 설정
💡 Provider
- Redux 스토어를 React 애플리케이션의 모든 컴포넌트에 주입하는 역할을 수행합니다.
💡 PersistGate
- Redux 스토어의 상태를 로컬 스토리지나 세션 스토리지에 저장하고(React Native 내에서는 AsyncStore와 같은 공간에 저장) 재로딩 시 복원하는 역할을 수행합니다.
💡 Provider 구성 및 설정
- App 페이지 최상위에 Provider로 스토어와 PersistGate를 등록합니다.
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import { Persistor, Store } from "modules/redux/Stroe";
const App = () => {
return (
// Redux-Store
<Provider store={Store}>
{/* Redux-Persist */}
<PersistGate persistor={Persistor}>
<NavigationContainer>
{/* Stack Navigation Element */}
<StackNavigator />
</NavigationContainer>
</PersistGate>
</Provider>
)
}
export default App;
4) 구성 결과 확인하기
1. 상태 갱신하기
💡 상태 갱신하기
- useDispatch()를 통해서 Redux 저장소를 확인하여서 정보를 세팅합니다.
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 구조에 맞게 메모리 데이터를 지워주는 것이 좋습니다.
💡 앱 정보 선택 - 저장공간 탭 선택
💡 '데이터 삭제' 버튼을 선택하여 데이터를 삭제한 후에 수행합니다.
오늘도 감사합니다. 😀
반응형