๊ฐ๋ฐ์ ์ฒ์ ์งํํ ๋๋ ๋ฆฌ๋์ค ๋ด์ฉ์ ํ ํ์ผ์๋ค๊ฐ ๋ชจ์๋๋ค๊ฐ,
์ธํด ํ๋ฉด์ ๋๋ ํ ๋ง ํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ์๋๋ฐ ๋ ์จ๋จน์ ์ผ์ด ์๊ฒจ ๊ธฐ๋กํด๋๋ค.
Redux๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ๋ฅผ ํ๊ณณ์์ ๊ด๋ฆฌํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ ๋ ์ ์ฉํ๋ค.
1๏ธโฃ Redux ํ์ผ ๊ตฌ์กฐ (in React typescript)
/redux
/actions # ์ก์
์ ์ (์ด๋ฒคํธ ๋ฐ์ ์ ํ์ํ ๋ฐ์ดํฐ ์ ์)
categoryActions.ts
/reducers # ๋ฆฌ๋์ ์ ์ (์ํ๊ฐ ์ด๋ป๊ฒ ๋ณ๊ฒฝ๋ ์ง ๊ฒฐ์ )
categoryReducer.ts
store.ts # ์คํ ์ด ์ค์ (์ ์ฒด ์ํ ๊ด๋ฆฌ)
๊ฐ ํ์ผ์ Redux์ ํต์ฌ ์์์ธ ์ก์ (Actions), ๋ฆฌ๋์(Reducers), ์คํ ์ด(Store)๋ฅผ ๋ด๋นํ๋ค.
2๏ธโฃ ํ์ผ๋ณ ์ญํ
๐ redux/actions/categoryActions.ts
Redux์์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ค๋ฉด "์ก์ (Action)"์ด ํ์ํ๋ค.
์ก์ ์ ์ด๋ค ์ํ๋ฅผ ๋ณ๊ฒฝํ ๊ฒ์ธ์ง ์๋ ค์ฃผ๋ "๋ฉ์์ง" ์ญํ ์ ํ๋ค.
import { createAction } from "@reduxjs/toolkit";
export const setCategories = createAction<string[]>("SET_CATEGORIES");
โ
setCategories๋ ์นดํ
๊ณ ๋ฆฌ ๋ฆฌ์คํธ๋ฅผ ๋ณ๊ฒฝํ๋ ์ก์
์ ์์ฑํ๋ ํจ์์ด๋ค.
โ
"SET_CATEGORIES"๋ผ๋ ํ์
์ ๊ฐ์ง ์ก์
์ ๋ง๋ค๊ณ , string[] ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ์ ์๋ค.
๐ redux/reducers/categoryReducer.ts
Reducer๋ ์ก์ ์ ๋ฐ์์ ์ํ๋ฅผ ์ค์ ๋ก ๋ณ๊ฒฝํ๋ ์ญํ ์ ํ๋ค.
import { createReducer } from "@reduxjs/toolkit";
import { setCategories } from "../actions/categoryActions";
interface CategoryState {
categoryList: string[];
}
const initialState: CategoryState = {
categoryList: [],
};
const categoryReducer = createReducer(initialState, (builder) => {
builder.addCase(setCategories, (state, action) => {
state.categoryList = action.payload;
});
});
export default categoryReducer;
โ
initialState: ์ด๊ธฐ ์ํ ๊ฐ (categoryList ๋ฐฐ์ด)
โ
createReducer: setCategories ์ก์
์ด ํธ์ถ๋๋ฉด categoryList๋ฅผ ๋ณ๊ฒฝ
โ
action.payload: ์ก์
์ด ์ ๋ฌํ ๋ฐ์ดํฐ (string[])
๐ store.ts
์คํ ์ด(Store)๋ Redux์ ์ค์ ์ ์ฅ์์ด๋ค. ๋ชจ๋ ์ํ์ ๋ฆฌ๋์๋ฅผ ๋ชจ์์ ๊ด๋ฆฌํ๋ค.
import { configureStore } from "@reduxjs/toolkit";
import categoryReducer from "./reducers/categoryReducer";
const store = configureStore({
reducer: {
category: categoryReducer, // ์ํ ์ด๋ฆ์ category๋ก ์ค์
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export default store;
โ
configureStore: ์ฌ๋ฌ ๋ฆฌ๋์๋ฅผ ํฉ์ณ์ Redux ์คํ ์ด๋ฅผ ์์ฑ
โ
RootState: Redux ์ํ์ ํ์
์ ์
โ
store.dispatch: ์ก์
์ Redux์ ์ ๋ฌํ๋ ํจ์
3๏ธโฃ Redux ๋ณ์ ์๋ ๋ฐฉ์
- ์ปดํฌ๋ํธ์์ dispatch(setCategories([...]) ์คํ
- ์๋ก์ด ์นดํ ๊ณ ๋ฆฌ ๋ฆฌ์คํธ๋ฅผ Redux์ ์ ๋ฌ
- Reducer๊ฐ setCategories ์ก์
์ ๊ฐ์งํ๊ณ state.categoryList ๋ณ๊ฒฝ
- categoryList๊ฐ ์๋ก์ด ๋ฐ์ดํฐ๋ก ์ ๋ฐ์ดํธ๋จ
- ์ปดํฌ๋ํธ์์ useSelector(state => state.category.categoryList)๋ก ์ํ ๊ฐ์ ธ์ค๊ธฐ
- ๋ณ๊ฒฝ๋ ์ํ๋ฅผ ์ปดํฌ๋ํธ์์ ์ฌ์ฉ ๊ฐ๋ฅ
4๏ธโฃ Redux ๋ณ์๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
Redux์ ์ํ๋ฅผ React ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ๋ ค๋ฉด useSelector์useDispatch๋ฅผ ํ์ฉํด์ผ ํ๋ค.
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { setCategories } from "../redux/actions/categoryActions";
import { RootState } from "./redux/store";
const CategoryComponent: React.FC = () => {
const dispatch = useDispatch();
const categoryList = useSelector((state: RootState) => state.category.categoryList);
const updateCategories = () => {
dispatch(setCategories(["Food", "Electronics", "Clothing"]));
};
return (
<div>
<h1>Categories</h1>
<ul>
{categoryList.map((category, index) => (
<li key={index}>{category}</li>
))}
</ul>
<button onClick={updateCategories}>Update Categories</button>
</div>
);
};
export default CategoryComponent;
โ
useSelector๋ฅผ ์ฌ์ฉํด Redux ์ํ(categoryList)๋ฅผ ๊ฐ์ ธ์จ๋ค.
โ
useDispatch๋ฅผ ์ฌ์ฉํด setCategories ์ก์
์ ํธ์ถํ๊ณ ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ค.
โ
๋ฒํผ์ ํด๋ฆญํ๋ฉด ์นดํ
๊ณ ๋ฆฌ ๋ฆฌ์คํธ๊ฐ ๋ณ๊ฒฝ๋๋ค.