๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

ํ”„๋ก ํŠธ์—”๋“œ/React

Redux ์—์„œ ๋น„๋™๊ธฐ ์ƒํƒœ ๋ณ€๊ฒฝ ์ฒ˜๋ฆฌ์— Redux-thunk ๋ฅผ ์ด์šฉํ•ด์•ผํ•˜๋Š” ์ด์œ 

728x90

Redux๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋™๊ธฐ์ ์ธ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด ์„ค๊ณ„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์—, API ํ˜ธ์ถœ ๊ฐ™์€ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ง์ ‘ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค.
redux-thunk๋Š” Redux์—์„œ ๋น„๋™๊ธฐ ์ž‘์—…์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ๋ฏธ๋“ค์›จ์–ด๋ผ๊ณ  ํ•œ๋‹ค.

 

 

๊ทธ๋Ÿฐ๋ฐ Redux ์—์„œ ๊ตณ์ด Redux-thunk ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์ƒํƒœ ๋ณ€๊ฒฝ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผํ•˜๋Š” ์ด์œ ๊ฐ€ ๊ถ๊ธˆํ•ด์กŒ๋‹ค.

 

 

Redux ์™ธ๋ถ€์—์„œ API ์š”์ฒญ์„ ์ฃผ๊ณ  ๋ฐ›๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋งŒ Redux๋กœ ๋ณด๋‚ด์–ด ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ (dispatch) ํ•ด๋„ ๋˜๋Š”๊ฑฐ ์•„๋‹๊นŒ?

 

 

์ฆ‰, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„๊ตํ–ˆ์„ ๋•Œ Redux-thunk ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์— ์–ด๋–ค ์ด์ ์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ด์กŒ๋‹ค.

// ์ปดํฌ๋„ŒํŠธ์—์„œ ๋น„๋™๊ธฐ ์š”์ฒญ๊ณผ ์ƒํƒœ๋ฅผ ๋กœ์ปฌ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ์˜ˆ์‹œ
const MyComponent = () => {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const dispatch = useDispatch();

  const fetchData = async () => {
    setLoading(true);
    try {
      const response = await apiRequest();
      dispatch(updateData(response.data)); // ์š”์ฒญ ์„ฑ๊ณต ์‹œ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
    } catch (err) {
      setError(err.message); // ์š”์ฒญ ์‹คํŒจ ์‹œ ์—๋Ÿฌ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchData();
  }, []);
};

redux-thunk๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์ƒํƒœ ๋ณ€๊ฒฝ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ์ด์œ 

Redux Toolkit์—์„œ redux-thunk๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์ƒํƒœ ๋ณ€๊ฒฝ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ์ด์œ ๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์˜ ์ „ํ›„ ์ƒํƒœ๋ฅผ Redux์—์„œ ๊ด€๋ฆฌํ•˜๊ณ , ์ผ๊ด€๋œ ์ƒํƒœ ๊ด€๋ฆฌ ํ๋ฆ„์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ์ด๋‹ค. ์™ธ๋ถ€์—์„œ ๋น„๋™๊ธฐ API ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ์„ฑ๊ณต ์‹œ์—๋งŒ Redux ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๋ฐฉ์‹๋„ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, redux-thunk๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์ ์ด ์žˆ๋‹ค.

1. ๋กœ๋”ฉ ์ƒํƒœ์™€ ์—๋Ÿฌ ์ƒํƒœ ๊ด€๋ฆฌ

๋น„๋™๊ธฐ ์š”์ฒญ์—๋Š” ์ฃผ๋กœ ์„ธ ๊ฐ€์ง€ ์ƒํƒœ๊ฐ€ ์กด์žฌํ•œ๋‹ค.

  • ์š”์ฒญ์ด ์‹œ์ž‘๋จ (loading ์ƒํƒœ)
  • ์š”์ฒญ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋จ (success ์ƒํƒœ)
  • ์š”์ฒญ์ด ์‹คํŒจํ•จ (error ์ƒํƒœ)

์˜ˆ๋ฅผ ๋“ค์–ด:

  • redux-thunk๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๋น„๋™๊ธฐ ์ž‘์—…์˜ ๊ฐ ๋‹จ๊ณ„์— ๋”ฐ๋ผ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.
  • API ํ˜ธ์ถœ์ด ์‹œ์ž‘๋˜๋ฉด loading ์ƒํƒœ๋ฅผ true๋กœ ์„ค์ •
  • API ํ˜ธ์ถœ์ด ์„ฑ๊ณตํ•˜๋ฉด loading์„ false๋กœ ์„ค์ •ํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ์ƒํƒœ์— ์ €์žฅ
  • API ํ˜ธ์ถœ์ด ์‹คํŒจํ•˜๋ฉด loading์„ false๋กœ ์„ค์ •ํ•˜๊ณ , ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ƒํƒœ์— ์ €์žฅ
// slice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

// createAsyncThunk๋ฅผ ์‚ฌ์šฉํ•ด ๋น„๋™๊ธฐ ์•ก์…˜ ์ƒ์„ฑ
export const fetchData = createAsyncThunk(
'data/fetchData',
async (_, thunkAPI) => {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data; // fulfilled ์ƒํƒœ์˜ payload๋กœ ์ „๋‹ฌ๋จ
}
);

// createSlice๋ฅผ ํ†ตํ•ด ๋ฆฌ๋“€์„œ์™€ ์•ก์…˜ ์ •์˜
const dataSlice = createSlice({
name: 'data',
initialState: {
data: null,
loading: false,
error: null,
},
reducers: {
// ๋™๊ธฐ ์•ก์…˜์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์—ฌ๊ธฐ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Œ
},
extraReducers: (builder) => {
builder
.addCase(fetchData.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchData.fulfilled, (state, action) => {
state.loading = false;
state.data = action.payload;
})
.addCase(fetchData.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
});
},
});

export default dataSlice.reducer;
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchData } from './slice';

const DataComponent = () => {
  const dispatch = useDispatch();
  const { data, loading, error } = useSelector((state) => state.data);

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

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

  return (
    <div>
      <h1>Data</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
};

export default DataComponent;

 

=> ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ์—์„œ ๋กœ๋”ฉ ์Šคํ”ผ๋„ˆ๋ฅผ ํ‘œ์‹œํ•˜๊ฑฐ๋‚˜, ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ฃผ๋Š” ๋“ฑ ๋ณด๋‹ค ํ’๋ถ€ํ•œ UX๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.

2. ์ƒํƒœ์˜ ์ผ๊ด€์„ฑ ์œ ์ง€

 

๋น„๋™๊ธฐ ์š”์ฒญ์„ ์™ธ๋ถ€์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ์—๋งŒ Redux ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ฉด, ์ƒํƒœ ๋ณ€ํ™”์˜ ํ๋ฆ„์ด Redux์—์„œ ๊ด€๋ฆฌ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ƒํƒœ์˜ ์ผ๊ด€์„ฑ์ด ๊นจ์งˆ ์œ„ํ—˜์ด ์žˆ๋‹ค.

  • ์™ธ๋ถ€์—์„œ API ์š”์ฒญ์ด ์„ฑ๊ณตํ–ˆ์ง€๋งŒ Redux ์ƒํƒœ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋ˆ„๋ฝ๋˜๊ฑฐ๋‚˜, ๋„คํŠธ์›Œํฌ ์ง€์—ฐ์œผ๋กœ ์ธํ•ด ๋Šฆ๊ฒŒ ๋„์ฐฉํ•œ ์‘๋‹ต์ด ์ƒํƒœ๋ฅผ ์ž˜๋ชป ๋ฎ์–ด์“ฐ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Redux๋Š” ์ƒํƒœ์˜ ๋‹จ์ผ ์ง„์‹ค ์†Œ์Šค(single source of truth)๋กœ์„œ ๋™์ž‘ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๋น„๋™๊ธฐ ์ž‘์—…์˜ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.
  • redux-thunk๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ๋กœ์ง์„ Redux ์•ˆ์—์„œ ๊ด€๋ฆฌํ•˜๋ฉด, ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ Redux ํ๋ฆ„์— ํ†ตํ•ฉ๋˜์–ด ์ƒํƒœ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋น„๋™๊ธฐ ์š”์ฒญ์„ ์™ธ๋ถ€์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ์—๋งŒ Redux ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ๋ฅผ ์ดํ•ดํ•˜๋ ค๋ฉด, ์ƒํƒœ์˜ ์ผ๊ด€์„ฑ์ด ๊นจ์งˆ ์œ„ํ—˜์ด ์–ด๋–ค ์ƒํ™ฉ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณผ ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

 

1) ๋„คํŠธ์›Œํฌ ์ง€์—ฐ ๋˜๋Š” ์‹คํŒจ๋กœ ์ธํ•œ ์ƒํƒœ ๋ถˆ์ผ์น˜

์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž๊ฐ€ ๋‘ ๋ฒˆ ์—ฐ์†์œผ๋กœ "๋ฐ์ดํ„ฐ ๋กœ๋“œ" ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ๋น„๋™๊ธฐ ์š”์ฒญ์ด ๋‘ ๋ฒˆ ๋ฐœ์ƒํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด์ž.

  • ์ฒซ ๋ฒˆ์งธ ์š”์ฒญ์ด ์„œ๋ฒ„์— ๋„๋‹ฌํ•˜์ง€๋งŒ ๋„คํŠธ์›Œํฌ ์ง€์—ฐ์œผ๋กœ ์ธํ•ด ์‘๋‹ต์ด ๋Šฆ์–ด์ง€๊ณ ,
  • ๋‘ ๋ฒˆ์งธ ์š”์ฒญ์€ ๋น ๋ฅด๊ฒŒ ์‘๋‹ต์„ ๋ฐ›์•„ ์„ฑ๊ณต์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

์ด ๊ฒฝ์šฐ, ๋น„๋™๊ธฐ ์š”์ฒญ์„ ์™ธ๋ถ€์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋‘ ๋ฒˆ์งธ ์š”์ฒญ์˜ ์„ฑ๊ณต ์‘๋‹ต๋งŒ Redux ์ƒํƒœ์— ๋ฐ˜์˜ํ•œ๋‹ค๋ฉด ๋ฌธ์ œ๊ฐ€ ์—†์–ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋‚˜์ค‘์— ์ฒซ ๋ฒˆ์งธ ์š”์ฒญ์ด ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•  ๊ฒฝ์šฐ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ์‹œ

// ์ฒซ ๋ฒˆ์งธ ์š”์ฒญ์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋Šฆ๊ฒŒ ๋„์ฐฉํ•˜์—ฌ ์ƒํƒœ๋ฅผ ๋ฎ์–ด์“ฐ๋Š” ์ƒํ™ฉ
dispatch(fetchDataSuccess(secondResponseData)); // ๋‘ ๋ฒˆ์งธ ์š”์ฒญ ๊ฒฐ๊ณผ
dispatch(fetchDataSuccess(firstResponseData));  // ์ฒซ ๋ฒˆ์งธ ์š”์ฒญ ๊ฒฐ๊ณผ (๋Šฆ๊ฒŒ ๋„์ฐฉ)

์ด๋ ‡๊ฒŒ ๋˜๋ฉด Redux ์ƒํƒœ์—๋Š” ๊ฐ€์žฅ ์ตœ์‹  ์ƒํƒœ๊ฐ€ ์•„๋‹Œ, ์ฒซ ๋ฒˆ์งธ ์š”์ฒญ์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋‚จ๊ฒŒ ๋œ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ํ™”๋ฉด์—์„œ ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๊ฒŒ ๋˜๋ฉฐ, ์ƒํƒœ์˜ ์ผ๊ด€์„ฑ์ด ๊นจ์ง„ ๊ฒƒ์„ ๋Š๋ผ๊ฒŒ ๋œ๋‹ค.

2) ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋™์ผํ•œ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์‚ฌ์šฉํ•  ๋•Œ

Redux ์ƒํƒœ๋Š” ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์— ๊ณต์œ ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋™์ผํ•œ ๋น„๋™๊ธฐ ์ž‘์—…์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ž์ฃผ ๋ฐœ์ƒํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ๋˜์–ด ์žˆ์„ ๋•Œ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์ด ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋งŒ์•ฝ ๋น„๋™๊ธฐ ์š”์ฒญ์„ ์™ธ๋ถ€์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ์—๋งŒ Redux ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค๋ฉด, ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋น„์Šทํ•œ ์š”์ฒญ์ด ์ค‘๋ณต๋˜๊ฑฐ๋‚˜ ์„œ๋กœ ์ถฉ๋Œํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง„๋‹ค.

์˜ˆ์‹œ

  • ์ปดํฌ๋„ŒํŠธ A์™€ ์ปดํฌ๋„ŒํŠธ B๊ฐ€ ๋™์‹œ์— ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค.
  • ๋‘ ์ปดํฌ๋„ŒํŠธ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ด๋ฐ์— API ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์„ฑ๊ณต ์‹œ์—๋งŒ Redux์— ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

์ด ๊ฒฝ์šฐ, ์ปดํฌ๋„ŒํŠธ A์˜ ์š”์ฒญ๊ณผ ์ปดํฌ๋„ŒํŠธ B์˜ ์š”์ฒญ์ด ๋™์‹œ์— ์„ฑ๊ณตํ•  ์ˆ˜๋„ ์žˆ๊ณ , ํ•˜๋‚˜๋Š” ์„ฑ๊ณตํ•˜๊ณ  ํ•˜๋‚˜๋Š” ์‹คํŒจํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ƒํƒœ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋น„๋™๊ธฐ ์š”์ฒญ์˜ ์„ฑ๊ณต ์—ฌ๋ถ€์—๋งŒ ์˜์กดํ•  ๊ฒฝ์šฐ, ๊ฐ ์š”์ฒญ์˜ ์‘๋‹ต ์ˆœ์„œ์™€ ์„ฑ๊ณต/์‹คํŒจ ์—ฌ๋ถ€์— ๋”ฐ๋ผ Redux ์ƒํƒœ๊ฐ€ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค.

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

3) ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ ๋‹จ์ผ ์ง„์‹ค ์†Œ์Šค๊ฐ€ ์•„๋‹Œ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ๊ด€๋ฆฌ๋จ

Redux์˜ ํ•ต์‹ฌ ์›์น™ ์ค‘ ํ•˜๋‚˜๋Š” ๋‹จ์ผ ์ง„์‹ค์˜ ์†Œ์Šค(single source of truth)์ด๋‹ค. ์ƒํƒœ๊ฐ€ ์ค‘์•™์—์„œ ์ผ๊ด€๋˜๊ฒŒ ๊ด€๋ฆฌ๋˜์–ด์•ผ๋งŒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋กœ ์œ ์ง€๋  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋น„๋™๊ธฐ ์š”์ฒญ์ด ์™ธ๋ถ€์—์„œ ๊ด€๋ฆฌ๋˜๊ณ , ์„ฑ๊ณต ์‹œ์—๋งŒ Redux์— ๊ฒฐ๊ณผ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ฉด ์ƒํƒœ ๋ณ€ํ™”๊ฐ€ Redux ์™ธ๋ถ€์™€ ๋‚ด๋ถ€ ์–‘์ชฝ์—์„œ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค. ์ด๋กœ ์ธํ•ด ์ƒํƒœ์˜ ๋ณ€๊ฒฝ ํ๋ฆ„์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์ƒํƒœ๊ฐ€ ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋œ๋‹ค.

3. ์ค‘์•™ ์ง‘์ค‘์‹ ๋น„๋™๊ธฐ ๋กœ์ง ๊ด€๋ฆฌ

redux-thunk๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  ๋น„๋™๊ธฐ ๋กœ์ง์ด Redux์˜ ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜ ์•ˆ์— ์ •์˜๋˜๋ฏ€๋กœ, ๋น„๋™๊ธฐ ์ž‘์—…์ด ์–ด๋””์„œ ๋ฐœ์ƒํ•˜๊ณ  ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™”ํ•˜๋Š”์ง€ ์ฝ”๋“œ ๊ตฌ์กฐ๊ฐ€ ๋” ๋ช…ํ™•ํ•ด์ง„๋‹ค. ๋น„๋™๊ธฐ ์š”์ฒญ์„ ์™ธ๋ถ€์—์„œ ์ฒ˜๋ฆฌํ•  ๊ฒฝ์šฐ, ์š”์ฒญ ์œ„์น˜๊ฐ€ ์—ฌ๊ธฐ์ €๊ธฐ ํฉ์–ด์งˆ ์ˆ˜ ์žˆ์–ด ์ฝ”๋“œ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ๋‹ค.

 

๋งŒ์ผ ์™ธ๋ถ€์—์„œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์„ฑ๊ณตํ•  ๋•Œ๋งŒ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ฉด, Redux์—์„œ๋Š” ์š”์ฒญ ์ค‘์— ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€ํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ƒํƒœ ๋ณ€ํ™”์˜ ์ „์ฒด ํ๋ฆ„์„ ์ถ”์ ํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง„๋‹ค. ํŠนํžˆ loading ์ƒํƒœ์™€ error ์ƒํƒœ๊ฐ€ Redux์— ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, UI์—์„œ ๋กœ๋”ฉ ์Šคํ”ผ๋„ˆ๋ฅผ ํ‘œ์‹œํ•˜๊ฑฐ๋‚˜ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๋“ฑ์˜ ์ฒ˜๋ฆฌ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ์‹œ

๋งŒ์•ฝ Redux์—์„œ loading ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ํ‘œ์‹œํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ useState๋กœ ๊ด€๋ฆฌํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

// ์ปดํฌ๋„ŒํŠธ์—์„œ ๋น„๋™๊ธฐ ์š”์ฒญ๊ณผ ์ƒํƒœ๋ฅผ ๋กœ์ปฌ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ์˜ˆ์‹œ
const MyComponent = () => {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const dispatch = useDispatch();

  const fetchData = async () => {
    setLoading(true);
    try {
      const response = await apiRequest();
      dispatch(updateData(response.data)); // ์š”์ฒญ ์„ฑ๊ณต ์‹œ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
    } catch (err) {
      setError(err.message); // ์š”์ฒญ ์‹คํŒจ ์‹œ ์—๋Ÿฌ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    fetchData();
  }, []);
};

 

์ด ๊ฒฝ์šฐ loading๊ณผ error ์ƒํƒœ๊ฐ€ Redux์˜ ์ค‘์•™ ์ƒํƒœ ๊ด€๋ฆฌ ํ๋ฆ„์— ํฌํ•จ๋˜์ง€ ์•Š์•„, ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ด ์ƒํƒœ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค. ๋˜ํ•œ Redux DevTools์—์„œ ์ƒํƒœ ๋ณ€ํ™”์˜ ํ๋ฆ„์„ ํ™•์ธํ•  ์ˆ˜ ์—†์–ด ๋””๋ฒ„๊น…์ด ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ๋‹ค.

4. Redux DevTools์™€์˜ ์—ฐ๋™

redux-thunk๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Redux DevTools์—์„œ ์•ก์…˜์˜ ํ๋ฆ„์„ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋‹ค. pending, fulfilled, rejected ๋“ฑ์˜ ์•ก์…˜์ด ์ˆœ์„œ๋Œ€๋กœ ๋””์ŠคํŒจ์น˜๋˜๋Š” ๊ณผ์ •์„ ์‹œ๊ฐ์ ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด, ๋น„๋™๊ธฐ ์ž‘์—…์„ ๋” ์‰ฝ๊ฒŒ ๋””๋ฒ„๊น…ํ•  ์ˆ˜ ์žˆ๋‹ค.

5. ์•ก์…˜ ์ฒด์ด๋‹ ๋ฐ ์ƒํƒœ์— ๋”ฐ๋ฅธ ๋น„๋™๊ธฐ ๋กœ์ง ์ฒ˜๋ฆฌ

redux-thunk๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Redux ์ƒํƒœ์— ๋”ฐ๋ผ ์กฐ๊ฑด๋ถ€ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํŠน์ • ์ƒํƒœ์ผ ๋•Œ๋งŒ API ์š”์ฒญ์„ ๋ณด๋‚ด๊ฑฐ๋‚˜, ์ด์ „ ์š”์ฒญ์˜ ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ ์ƒˆ๋กœ์šด ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

   export const conditionalFetchData = () => {
     return (dispatch, getState) => {
       const { data } = getState();
       if (!data) {
         dispatch(fetchData());
       }
     };
   };

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

๊ฒฐ๋ก 

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