Skip to content

ssi02014/redux-toolkit-tutorial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

4 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ’ป 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๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค.
// 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์€ ์•ก์…˜ ํƒ€์ž… ๋ฌธ์ž์—ด์„ ์ธ์ž๋กœ ๋ฐ›๊ณ , ํ•ด๋‹น ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ์•ก์…˜ ์ƒ์„ฑ์žํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
// 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 ์˜ˆ์ œ ๋‹จ์ˆœํ™”
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ํ•„๋“œ์—†์ด ์ง์ ‘ ์•ก์…˜ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
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๋ผ๋Š” ๊ฐ์ฒด ๋‚ด๋ถ€์—์„œ ์ƒ์„ฑ๋œ ์•ก์…˜ ์ƒ์„ฑํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
const counterSlice = createSlice({
  name: "counter",
  initialState: 0,
  reducers: {
    increment: (state) => state + 1,
    decrement: (state) => state - 1,
  },
});

const store = configureStore({
  reducer: counterSlice.reducer,
});
  • ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ, ES6 ๋”•์ŠคํŠธ๋Ÿญ์ฒ˜๋ง ๊ตฌ๋ฌธ์„ ์ด์šฉํ•˜์—ฌ ์•ก์…˜ ์ƒ์„ฑ์ž ํ•จ์ˆ˜์™€ reducer๋ฅผ ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๊ธฐ๋ฅผ ์›ํ•œ๋‹ค.
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์— ๋Œ€ํ•œ ์ทจ์†Œ ์ž‘์—…์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
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

About

๐ŸŽ‡ reactJS, Redux Toolkit Tutorial

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published