Front-end/React

[React] Redux Thunk: ๋ฏธ๋“ค์›จ์–ด์˜ ๋ง›๊น”๋‚˜๋Š” ์กฐ๋ฏธ๋ฃŒ ๐Ÿฒ

xeunnie 2025. 1. 7. 01:00
728x90
๋ฐ˜์‘ํ˜•

Redux Thunk ํ†บ์•„๋ณด๊ธฐ! ๐Ÿฒ

Redux Thunk๋Š” Redux์—์„œ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ฏธ๋“ค์›จ์–ด์ž…๋‹ˆ๋‹ค. “Thunk”๋ผ๋Š” ์ด๋ฆ„์€ ๋‹ค์†Œ ์‹ ๋น„๋กญ๊ฒŒ ๋“ค๋ฆด ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ฐ„๋‹จํžˆ ๋งํ•ด ์•ก์…˜์„ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋””์ŠคํŒจ์น˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋„๊ตฌ๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ผ์š”.

 

์ด ๊ธ€์—์„œ๋Š” Redux Thunk๊ฐ€ ์™œ ํ•„์š”ํ•œ์ง€, ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋‹ค๋ฃฐ๊ฒŒ์š”. ์ค€๋น„๋˜์…จ๋‚˜์š”? ์ถœ๋ฐœ~! ๐Ÿš€


๐Ÿ” Redux์—์„œ ๋น„๋™๊ธฐ ์ž‘์—…์ด ์™œ ํ•„์š”ํ•œ๊ฐ€?

Redux๋Š” ์ˆœ์ˆ˜ํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, ์•ก์…˜(Action)์ด ๋ฐœ์ƒํ•˜๋ฉด ๋ฆฌ๋“€์„œ(Reducer)๊ฐ€ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด UI๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์ฃ .

 

ํ•˜์ง€๋งŒ… ์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๊ฐ€ ํ•˜๋‚˜ ์žˆ์–ด์š”:

 

Redux๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋™๊ธฐ ์ž‘์—…๋งŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด API ํ˜ธ์ถœ ๊ฐ™์€ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์ž–์•„์š”? ์—ฌ๊ธฐ์„œ Redux Thunk๊ฐ€ ๋“ฑ์žฅํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ’ก Redux Thunk๋ž€?

Thunk๋Š” ์›๋ž˜ ํ•จ์ˆ˜๋ฅผ ๋ž˜ํ•‘ํ•ด์„œ ๋‚˜์ค‘์— ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“  ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. Redux Thunk๋Š” ์ด ๊ฐœ๋…์„ Redux์— ์ ์šฉํ•˜์—ฌ ์•ก์…˜ ์ƒ์„ฑ์ž๊ฐ€ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

 

๊ธฐ๋ณธ์ ์œผ๋กœ Redux๋Š” ๊ฐ์ฒด๋งŒ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, Redux Thunk๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๊ทธ ํ•จ์ˆ˜ ์•ˆ์—์„œ ๋น„๋™๊ธฐ ์ž‘์—…(API ํ˜ธ์ถœ ๋“ฑ)์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ์ž‘์—…์ด ๋๋‚œ ํ›„์— ์•ก์…˜์„ ๋””์ŠคํŒจ์น˜ํ•  ์ˆ˜ ์žˆ์–ด์š”.


โš™๏ธ ์„ค์น˜ ๋ฐ ์„ค์ •

Redux Thunk๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋ฏธ๋“ค์›จ์–ด๋กœ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

npm install redux-thunk

 

store๋ฅผ ์ƒ์„ฑํ•  ๋•Œ applyMiddleware๋ฅผ ํ†ตํ•ด Redux Thunk๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”:

import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import rootReducer from "./reducers";

const store = createStore(rootReducer, applyMiddleware(thunk));

export default store;

 

์ด์ œ Redux Thunk๋ฅผ ์‚ฌ์šฉํ•  ์ค€๋น„ ์™„๋ฃŒ! ๐ŸŽ‰


๐Ÿ“‹ Redux Thunk ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

Thunk์˜ ๊ธฐ๋ณธ ์•„์ด๋””์–ด๋Š” ์•ก์…˜ ๋Œ€์‹  ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์•ก์…˜ ์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

// ์ผ๋ฐ˜ ์•ก์…˜ ์ƒ์„ฑ์ž
const increment = () => ({ type: "INCREMENT" });

// Thunk ์•ก์…˜ ์ƒ์„ฑ์ž
const fetchData = () => {
  return async (dispatch) => {
    dispatch({ type: "FETCH_DATA_REQUEST" });
    try {
      const response = await fetch("https://api.example.com/data");
      const data = await response.json();
      dispatch({ type: "FETCH_DATA_SUCCESS", payload: data });
    } catch (error) {
      dispatch({ type: "FETCH_DATA_FAILURE", error });
    }
  };
};

 

๐Ÿ‘‰ ์—ฌ๊ธฐ์„œ fetchData๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์•ก์…˜ ์ƒ์„ฑ์ž์ž…๋‹ˆ๋‹ค.

์ด ํ•จ์ˆ˜๋Š” dispatch๋ฅผ ๋ฐ›์•„์„œ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์‹คํ–‰ํ•œ ํ›„, ์„ฑ๊ณต ๋˜๋Š” ์‹คํŒจ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์•ก์…˜์„ ๋””์ŠคํŒจ์น˜ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿš ๋น„๋™๊ธฐ ์ž‘์—… ๋‹จ๊ณ„๋ณ„ ์ฒ˜๋ฆฌ

๋น„๋™๊ธฐ ์ž‘์—…์„ Redux Thunk๋กœ ์ฒ˜๋ฆฌํ•  ๋•Œ๋Š” ๋ณดํ†ต ์„ธ ๊ฐ€์ง€ ๋‹จ๊ณ„๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค:

  1. ์š”์ฒญ ์‹œ์ž‘: ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹œ์ž‘ํ–ˆ์Œ์„ ์•Œ๋ฆฌ๋Š” ์•ก์…˜ ๋””์ŠคํŒจ์น˜
  2. ์š”์ฒญ ์„ฑ๊ณต: ๋ฐ์ดํ„ฐ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ๊ฐ€์ ธ์™”์Œ์„ ์•Œ๋ฆฌ๋Š” ์•ก์…˜ ๋””์ŠคํŒจ์น˜
  3. ์š”์ฒญ ์‹คํŒจ: ์š”์ฒญ ์ค‘ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Œ์„ ์•Œ๋ฆฌ๋Š” ์•ก์…˜ ๋””์ŠคํŒจ์น˜
// ๋ฆฌ๋“€์„œ ์˜ˆ์‹œ
const initialState = {
  loading: false,
  data: null,
  error: null,
};

function dataReducer(state = initialState, action) {
  switch (action.type) {
    case "FETCH_DATA_REQUEST":
      return { ...state, loading: true, error: null };
    case "FETCH_DATA_SUCCESS":
      return { ...state, loading: false, data: action.payload };
    case "FETCH_DATA_FAILURE":
      return { ...state, loading: false, error: action.error };
    default:
      return state;
  }
}

๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป ์‹ค์ „ ์˜ˆ์ œ: ์‚ฌ์šฉ์ž์˜ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ

์•ก์…˜ ์ƒ์„ฑ์ž

export const fetchUsers = () => {
  return async (dispatch) => {
    dispatch({ type: "FETCH_USERS_REQUEST" });

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/users");
      const users = await response.json();
      dispatch({ type: "FETCH_USERS_SUCCESS", payload: users });
    } catch (error) {
      dispatch({ type: "FETCH_USERS_FAILURE", error: error.message });
    }
  };
};

 

๋ฆฌ๋“€์„œ

const initialState = {
  loading: false,
  users: [],
  error: null,
};

function usersReducer(state = initialState, action) {
  switch (action.type) {
    case "FETCH_USERS_REQUEST":
      return { ...state, loading: true, error: null };
    case "FETCH_USERS_SUCCESS":
      return { ...state, loading: false, users: action.payload };
    case "FETCH_USERS_FAILURE":
      return { ...state, loading: false, error: action.error };
    default:
      return state;
  }
}

 

์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ

import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { fetchUsers } from "./actions";

function UserList() {
  const dispatch = useDispatch();
  const { loading, users, error } = useSelector((state) => state.users);

  useEffect(() => {
    dispatch(fetchUsers());
  }, [dispatch]);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

export default UserList;

โš ๏ธ Redux Thunk ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์ 

1. ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ํ•„์š” ์—†์„ ๊ฒฝ์šฐ

Redux Thunk๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๋™๊ธฐ ์ž‘์—…๋งŒ ์žˆ๋‹ค๋ฉด ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†์–ด์š”.

 

2. ๋„ˆ๋ฌด ๋งŽ์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง

Thunk ๋‚ด๋ถ€์—์„œ ๋„ˆ๋ฌด ๋งŽ์€ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ ์•ก์…˜ ์ƒ์„ฑ์ž๋ณด๋‹ค๋Š” ๋ฆฌ๋“€์„œ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค.

 

3. Redux Toolkit ํ™œ์šฉ

์ตœ๊ทผ์—๋Š” Redux Toolkit์ด ๊ธฐ๋ณธ์ ์œผ๋กœ Thunk๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์–ด ์„ค์ •์ด ๋” ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. Redux Toolkit๋„ ํ•œ๋ฒˆ ๊ฒ€ํ† ํ•ด ๋ณด์„ธ์š”.


๐Ÿ“š Redux Thunk vs Redux Saga

Redux Thunk์™€ ์ž์ฃผ ๋น„๊ต๋˜๋Š” ๋„๊ตฌ๋กœ๋Š” Redux Saga๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‘˜ ๋‹ค ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ๋•์ง€๋งŒ, ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค:

ํŠน์ง• Redux Thunk Redux Saga
์„ค์น˜ ๋ฐ ์‚ฌ์šฉ ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์  ์„ค์ •๊ณผ ์ฝ”๋“œ๊ฐ€ ๋” ๋ณต์žกํ•จ
๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ ๊ธฐ๋ฐ˜์œผ๋กœ ๋น„๋™๊ธฐ ์ž‘์—… ์ฒ˜๋ฆฌ ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ณต์žกํ•œ ์ž‘์—… ์ฒ˜๋ฆฌ
ํ•™์Šต ๊ณก์„  ๋‚ฎ์Œ ๋†’์Œ
์œ ์Šค ์ผ€์ด์Šค ๊ฐ„๋‹จํ•œ ๋น„๋™๊ธฐ ๋กœ์ง ๋ณต์žกํ•œ ๋น„๋™๊ธฐ ํ๋ฆ„

๐Ÿ”– ๊ฒฐ๋ก : Redux Thunk๋กœ ๊น”๋”ํ•œ ๋น„๋™๊ธฐ ๊ด€๋ฆฌ ๐ŸŽ‰

Redux Thunk๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์„ Redux์— ํ†ตํ•ฉํ•˜๊ธฐ ์œ„ํ•œ ํ›Œ๋ฅญํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ API ํ˜ธ์ถœ๋ถ€ํ„ฐ ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ํ๋ฆ„๊นŒ์ง€, Redux Thunk๋กœ ๊น”๋”ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ด ๋ณด์„ธ์š”.

 

๐ŸŒท์ „์„ค์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๋ด…์‹œ๋‹น!๐ŸŒท

728x90
๋ฐ˜์‘ํ˜•