Redux는 Context API가 본격적으로 나오기 전부터 사용되던 전역 상태 관리 라이브러리이다.
현재는 Redux 외에도 Recoil, MobX 등 다양한 상태 관리 라이브러리가 나와서 예전만큼 인기를 얻지 못하지만 많이 사용되고 있다.
Redux는 전역 상태 관리 뿐만 아니라 Flux 패턴 기반 데이터 흐름 제어를 할 수 있고, Middleware를 추가하여 Data Fetching이 가능하고, 프로젝트의 데이터 흐름을 일관적으로 관리할 수 있다.
Flux 패턴
Action -> Dispatcher -> Store -> View
- Action : 데이터의 변경을 발생시키는 행위 (Update)
- Dispatcher : 모든 데이터 흐름을 관리하고 Redux와 useReducer의 Reducer과 유사하다.
또한 Action이 발생 했을 때 Store를 어떻게 업데이트 할지 결정한다.
- Store : 어플리케이션의 상태를 저장하고 여러개의 Store를 가질 수 있다. (Redux는 단일 Store)
하지만 여러개의 Store는 서로 직접 변경할 수 없다.
- View : Store의 값이 변경되면 View가 갱신되고 직접적으로 Store 값을 변경할 수 없다. (단방향 데이터 흐름)
Redux
Flux 패턴을 참고하여 만든 라이브러리인 Redux는 다른 부분은 동일한데 Middleware가 추가되었다.
- Middleware : Action이 발생되었을 때 Reducer로 향하는 흐름을 중간에 관찰하거나, 가로채고 다른 작업을 할 수 있으며 이후에 Reducer로 액션을 발생 시킬 수 있다.
yarn add @reduxjs/toolkit react-redux
// Store/index.ts
import { configureStore } from '@reduxjs/toolkit'
import { useDispatch } from 'react-redux'
import { imageTypeReducer } from './imageTypeSlice'
export const store = configureStore({
reducer: {
imageType: imageTypeReducer
},
})
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
export const useAppDispatch = () => useDispatch<AppDispatch>()
// App.tsx
import { BrowserRouter } from "react-router-dom";
import PageHeader from "./Common/PageHeader";
import PageNavigator from "./PageNavigator";
import { Provider } from "react-redux";
import { store } from "./Store";
function App() {
return (
<>
<Provider store={store}>
<BrowserRouter>
<PageHeader />
<PageNavigator />
</BrowserRouter>
</Provider>
</>
);
}
export default App;
// store/imageTypeSlice.ts
import { PayloadAction, createSlice } from '@reduxjs/toolkit'
import { POKEMON_IMAGE_TYPE } from '../Constants'
export type PokemonImageKeyType = typeof POKEMON_IMAGE_TYPE[keyof typeof POKEMON_IMAGE_TYPE]
export interface ImageTypeState {
type: PokemonImageKeyType // TODO : imageType
}
const initialState: ImageTypeState = {
type: POKEMON_IMAGE_TYPE.FRONT_DEFAULT,
}
export const imageTypesSlice = createSlice({
name: 'imageType',
initialState,
reducers: {
changeImageType: (state, action: PayloadAction<ImageTypeState>) => {
state.type = action.payload.type
},
},
})
export const { changeImageType } = imageTypesSlice.actions
export const imageTypeReducer = imageTypesSlice.reducer
createAsyncThunk
Redux Toolkit에서 제공하는 편리한 유틸리티 함수로, 비동기 작업을 처리하는 Thunk 액션을 생성할 때 사용된다.
일반적으로 Redux 액션은 동기적인 작업을 처리하는데 사용된다. 그러나 비동기 작업 (예: API 호출)을 처리할 때는 Redux Thunk 미들웨어와 createAsyncThunk를 사용하면 코드가 간단해지고 유지보수가 쉬워진다.
export const fetchPokemons = createAsyncThunk(
'pokemon/fetchPokemons',
async (nextUrl?:string) => {
const response = await fetchPokemonsAPI(nextUrl)
return response
}
)
https://ko.redux.js.org/introduction/getting-started/
Redux 시작하기 | Redux
소개 > 시작하기: Redux를 배우고 사용하기 위한 자료
ko.redux.js.org
https://redux-toolkit.js.org/tutorials/quick-start
Quick Start | Redux Toolkit
redux-toolkit.js.org
https://redux-toolkit.js.org/api/createAsyncThunk#overview
createAsyncThunk | Redux Toolkit
redux-toolkit.js.org