An open API service indexing awesome lists of open source software.

https://github.com/ssi02014/redux-toolkit-tutorial

๐ŸŽ‡ reactJS, Redux Toolkit Tutorial
https://github.com/ssi02014/redux-toolkit-tutorial

Last synced: 8 months ago
JSON representation

๐ŸŽ‡ reactJS, Redux Toolkit Tutorial

Awesome Lists containing this project

README

          

# ๐Ÿ’ป Redux-toolkit-Tutorial

## ๐Ÿƒโ€โ™‚๏ธ Start

- yarn create react-app (ํ”„๋กœ์ ํŠธ ์ด๋ฆ„) --template redux
- yarn add @reduxjs/toolkit redux-devtools-extension
- yarn add @types/react-redux //ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ


## ๐Ÿ‘จโ€๐Ÿ’ป configureStore

- Redux Toolkit์—๋Š” Redux ์ฝ”๋“œ๋ฅผ ๋‹จ์ˆœํ™”ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋˜๋Š” ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋Šฅ ์ค‘ ์ฒซ ๋ฒˆ์žฌ๊ฐ€ `configureStore`์ด๋‹ค.
- ์ผ๋ฐ˜์ ์œผ๋กœ createStore()๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  root reducer ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜์—ฌ redux store๋ฅผ ๊ตฌ์„ฑํ•œ๋‹ค.
- Redux Toolkit์€ createStor()๋ฅผ ๋ž˜ํ•‘ํ•œ configureStore() ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์ด ํ•จ์ˆ˜๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ createStore()๊ณผ ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. ํ•˜์ง€๋งŒ configureStore()๋Š” store๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋‹จ๊ณ„์—์„œ ๋ช‡ ๊ฐ€์ง€ ์œ ์šฉํ•œ ๊ฐœ๋ฐœ ๋„๊ตฌ๊ฐ€ ์„ค์ •๋˜๋„๋ก ํ•œ๋‹ค.
- configureStore()๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ธ์ž ๋Œ€์‹  ์ด๋ฆ„์ด ์ง€์ •๋œ ํ•˜๋‚˜์˜ object๋ฅผ ์ธ์ž๋กœ ๋ฐ›์œผ๋ฏ€๋กœ, reducer ํ•จ์ˆ˜๋ฅผ reducer๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค.

```ts
// Before:
const store = createStore(counter);

// After:
const store = configureStore({
reducer: counter,
});

// Example
const reducer = {
...contractsReducer,
(...)
}

const rootReducer = combineReducers(reducer);
export const persistedReducer = persistReducer(persistConfig, rootReducer);
export const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: (...),
},
})
.prepend()
// prepend and concat calls can be chained
.concat(middlewares),
devTools: process.env.NODE_ENV !== "production",
});
```


## ๐Ÿ‘จโ€๐Ÿ’ป createAction

- createAction์€ ์•ก์…˜ ํƒ€์ž… ๋ฌธ์ž์—ด์„ ์ธ์ž๋กœ ๋ฐ›๊ณ , ํ•ด๋‹น ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ์•ก์…˜ ์ƒ์„ฑ์žํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

```js
// Before: ์•ก์…˜ type๊ณผ ์ƒ์„ฑํ•จ์ˆ˜๋ฅผ ๋ชจ๋‘ ์ž‘์„ฑ
const INCREMENT = "INCREMENT";

function incrementOriginal() {
return { type: INCREMENT };
}

console.log(incrementOriginal()); // {type: "INCREMENT"}

// After: createAction ์‚ฌ์šฉ
const incrementNew = createAction("INCREMENT");

console.log(incrementNew()); // {type: "INCREMENT"}
```

- createAction์„ ์‚ฌ์šฉํ•˜์—ฌ counter ์˜ˆ์ œ ๋‹จ์ˆœํ™”

```js
const increment = createAction("INCREMENT");
const decrement = createAction("DECREMENT");

function counter(state = 0, action) {
switch (action.type) {
case increment.type:
return state + 1;
case decrement.type:
return state - 1;
default:
return state;
}
}
```


## ๐Ÿ‘จโ€๐Ÿ’ป createReducer

- if๋ฌธ๊ณผ ๋ฐ˜๋ณต๋ฌธ์„ ํฌํ•จํ•˜์—ฌ reducer์—์„œ ์›ํ•˜๋Š” ์กฐ๊ฑด ๋…ผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์€ action.type ํ•„๋“œ๋ฅผ ํ™•์ธํ•˜๊ณ  ๊ฐ ์œ ํ˜•์— ๋Œ€ํ•ด ์ ์ ˆํ•œ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
- reducer๋Š” ์ดˆ๊ธฐ ์ƒํƒœ๊ฐ’์„ ์ œ๊ณตํ•˜๊ณ , ํ˜„์žฌ ์•ก์…˜๊ณผ ๊ด€๊ณ„์—†๋Š” ์ƒํƒœ๋Š” ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
- Redux Toolkit์—๋Š” `lookup Table` ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ reducer๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” createReducer()๊ฐ€ ์žˆ๋‹ค.
- createReducer() ๊ฐ์ฒด์˜ ๊ฐ ํ‚ค๋Š” redux์˜ ์•ก์…˜ type ๋ฌธ์ž์—ด์ด๋ฉฐ ๊ฐ’์€ reducerํ•จ์ˆ˜์ด๋‹ค.
- ์•ก์…˜ type ๋ฌธ์ž์—ด์„ ํ‚ค๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฏ€๋กœ `ES6 object computer ์†์„ฑ` ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ type๋ฌธ์ž์—ด ๋ณ€์ˆ˜๋กœ ํ‚ค๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
- computed ์†์„ฑ ๊ตฌ๋ฌธ์€ ๋‚ด๋ถ€์— ์žˆ๋Š” ๋ชจ๋“  ๋ณ€์ˆ˜์— ๋Œ€ํ•ด `toString()`์„ ํ˜ธ์ถœํ•˜๋ฏ€๋กœ `.type`ํ•„๋“œ์—†์ด ์ง์ ‘ ์•ก์…˜ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

```js
const increment = createAction("INCREMENT");
const decrement = createAction("DECREMENT");

const counter = createReducer(0, {
[increment]: (state) => state + 1,
[decrement]: (state) => state - 1,
});
```


## ๐Ÿ‘จโ€๐Ÿ’ป createSlice

- ์œ„์— ๋‚ด์šฉ์œผ๋กœ๋„ ๋‚˜์˜์ง€ ์•Š์ง€๋งŒ, createSlice๋กœ ๋” ํฐ ๋ณ€ํ™”๋ฅผ ์ค„ ์ˆ˜ ์žˆ๋‹ค.
- createSlice ํ•จ์ˆ˜๋Š” ๊ฐ์ฒด์— reducer ํ•จ์ˆ˜๋“ค์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๊ณ  ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์•ก์…˜ ํƒ€์ž… ๋ฌธ์ž์—ด๊ณผ ์•ก์…˜ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•œ๋‹ค.
- createSlice๋Š” ์ƒ์„ฑ๋œ reducer ํ•จ์ˆ˜๋ฅผ reducer๋ผ๋Š” ํ•„๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” `slice`๊ฐ์ฒด์™€ `actions`๋ผ๋Š” ๊ฐ์ฒด ๋‚ด๋ถ€์—์„œ ์ƒ์„ฑ๋œ ์•ก์…˜ ์ƒ์„ฑํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

```js
const counterSlice = createSlice({
name: "counter",
initialState: 0,
reducers: {
increment: (state) => state + 1,
decrement: (state) => state - 1,
},
});

const store = configureStore({
reducer: counterSlice.reducer,
});
```

- ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ, ES6 ๋”•์ŠคํŠธ๋Ÿญ์ฒ˜๋ง ๊ตฌ๋ฌธ์„ ์ด์šฉํ•˜์—ฌ ์•ก์…˜ ์ƒ์„ฑ์ž ํ•จ์ˆ˜์™€ reducer๋ฅผ ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๊ธฐ๋ฅผ ์›ํ•œ๋‹ค.

```js
export const { increment, decrement } = counterSlice.actions;
```




## ๐Ÿ‘จโ€๐Ÿ’ป createSlice(์ค‘๊ธ‰)

- createSlice ์˜ต์…˜
- name: ์ƒ์„ฑ ๋œ action types๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” prefix
- initialState: reducer์˜ ์ดˆ๊ธฐ ์ƒํƒœ
- reducers: key๋Š” action type ๋ฌธ์ž์—ด์ด ๋˜๊ณ  ํ•จ์ˆ˜๋Š” ํ•ด๋‹น ์•ก์…˜์ด dispatch๋  ๋•Œ ์‹คํ–‰๋  reducer์ด๋‹ค.
- ์˜ˆ๋กœ, `todos/addTodo`์•ก์…˜์ด dispatch๋  ๋•Œ addTodo Reducer๊ฐ€ ์ˆ˜ํ–‰๋œ๋‹ค.
- createSlice์™€ createReducer๋Š” `immer library`์˜ `produce`๋กœ ๋ž˜ํ•‘ํ•œ๋‹ค. ์ด๊ฒƒ์€ ์ด ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋Š” ๋ฆฌ๋“€์„œ ๋‚ด๋ถ€์˜ ์ƒํƒœ๋ฅผ `๋ณ€ํ˜•ํ•˜๋Š”` ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, immer๋Š” ์ƒํƒœ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋ถˆ๋ณ€ํ•˜๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋„๋ก ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค.(์ฆ‰, push ๊ฐ™์€ ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)


- createSclie๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

```
{
name: "todos",
reducer: (state, action) => newState,
actions: {
addTodo: (payload) => ({type: "todos/addTodo", payload}),
toggleTodo: (payload) => ({type: "todos/toggleTodo", payload})
},
caseReducers: {
addTodo: (state, action) => newState,
toggleTodo: (state, action) => newState,
}
}
```

- ๊ฐ ๋ฆฌ๋“€์„œ๋งˆ๋‹ค ์ ์ ˆํ•œ action ์ƒ์„ฑ์ž์™€ action type์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋ฏ€๋กœ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.


## ๐Ÿ‘จโ€๐Ÿ’ป createAsyncThunk

- `createAsyncThunk`๋ฅผ ์„ ์–ธํ•˜๊ฒŒ ๋˜๋ฉด ์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์„ ์–ธํ•œ ์•ก์…˜ ์ด๋ฆ„์— pending, fulfilled, rejected์˜ ์ƒํƒœ์— ๋Œ€ํ•œ action์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ฃผ๊ฒŒ ๋œ๋‹ค.
- AbortController๋ฅผ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— thunk๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ๋„ api์— ๋Œ€ํ•œ ์ทจ์†Œ ์ž‘์—…์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

```js
const fetchTodo = createAsyncThunk(
`todo/fetchTodo`, // ์•ก์…˜ ์ด๋ฆ„์„ ์ •์˜ํ•ด ์ฃผ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
async (todoId, thunkAPI) => {
// ๋น„๋™๊ธฐ ํ˜ธ์ถœ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
const response = await todoApi.fetchTodoInfo(todoId);
return response.data;
}
);

// fetchTodo.pending => todo/fetchTodo/pending
// fetchTodo.fulfilled => todo/fetchTodo/fulfilled
// fetchTodo.rejected => todo/fetchTodo/rejected
```