React 기록

리액트 redux-thunk를 사용한 비동기 처리

Dreaming Developer Student 2025. 5. 9. 09:55
SMALL

리액트 애플리케이션에서 상태 관리를 하다 보면, 서버와의 비동기 통신이 필요한 상황이 자주 발생합니다. 이때 redux-thunk를 사용하면 Redux 안에서 비동기 작업을 효율적으로 처리할 수 있습니다. 이번 글에서는 redux-thunk에 대해 알아보도록 하겠습니다.

📑목차
1. redux-thunk
1-1. redux-thunk란?
1-2. redux-thunk의 등장
1-3. redux-thunk의 동작
1-4. redux-thunk 문법
1-5. redux-thunk의 목적
1-6. Todo-List 실습

 

서론

Redux를 사용하다 보면 "비동기 로직은 어디에 작성해야할까"라는 고민을 하게 됩니다. 예를 들어, API 요청을 보내고 그 결과를 상태에 반영하려고 할 때, Redux의 기본 구조만으로는 이를 처리하기 어렵습니다. 그 이유는 Redux는 동기적으로 작동되기 때문입니다. 그래서 이것을 비동기적으로 처리할 수 있도록 도와주는 것이 바로 redux-thunk입니다. redux-thunk는 Redux의 미들웨어로, 액션 생성자 안에서 비동기 작업을 가능하게 해주고, API 호출 후의 흐름을 컨트롤할 수 있도록 도와줍니다. 이번 글에서는 redux-thunk가 무엇인지, 왜 필요한지, 그리고 어떻게 사용하는지를 예제와 함께 자세히 알아보겠습니다.

본론

1. redux-thunk

 

1-1. redux-thunk란?

리덕스(Redux)에서 비동기 작업을 처리할 수 있도록 해주는 미들웨어

 

1-2. redux-thunk의 등장

Redux는 동기적인 데이터흐름을 지원합니다. 비동기 작업(API 호출)을 처리할 수 없기 때문에 redux-thunk로 미들웨어를 추가하여 비동기 로직을 처리할 수 있게 되었습니다.

 

1-3. redux-thunk의 동작

  1. 액션 생성자가 함수를 반환
  2. redux-thunk 미들웨어가 이 함수를 감지하고 실행
  3. 해당 함수 안에서 비동기 작업 실행
  4. 비동기 작업 완료 후, 결과를 바탕으로 dispatch를 통해 적절한 액션을 다시 디스패치하여 상태를 업데이트한다.

참고!

액션 생성자 함란?

Redux에서 액션 객체를 생성하는 함수를 뜻합니다

 

> dispatch에 전달된 매개변수가 함수면 함수를 실행
> 실행된 함수에 매개변수로 dispatch, getState 두가지의 인자 값으로 전달한다.

```js
// thunk를 사용하기 이전
// thunk 쪽에서 로그인 로직 처리
dispatch({type : "LOGIN"})

// 액션 생성자
dispatch((dispatch, getState) => {
    // 비동기 로직 처리
    dispatch({type : "LOGIN"})
})

// 상태의 변화를 잠시 뒤로 미룬다.
// 비동기 로직을 처리한 뒤에 실행하기 위해서 지연시키는것.
// 디스패치 => 액션 생성자 => 리듀서 => 스토어 업데이트

 

1-4. redux-thunk의 문법

1. 액션 생성자가 함수를 반환하는 사용법

// 유저의 프로필 정보를 요청하는 로직
// getUserAction (nick) 매개변수로 받는다
// 매개변수를 받는 이유는 
// 함수인데 함수값을 반환
export const getUserAction = (nick) => {
    return async (dispatch, getState) => { // 여기서 비동기 로직 처리
        const { data } = await axios.get(`http://localhost:4000/
        userinfo?nick=${nick}`) // 비동기 요청 후 아래 코드 실행
        // 전역상태 업데이트
        dispatch({type : "USERINFO", payload : data})
    } 
    // 반환을 하는데 익명함수로 반환
}

 

코드를 보시면 액션 생성자 함수인 getUserAction이 있습니다. 매개변수로는 nick을 받고 함수 내부에서 익명함수를 반환하는 로직이 작성되어있습니다. 반환을 받으면서 반환된 익명함수는 redux-thunk에 의해 호출이되며 dispatch와 getState가 반환된 익명함수에 인자로 전달됩니다. 그리고 익명 함수 내부에서 비동기적으로 API 요청이 일어나고, 비동기 요청이 완료되면 dispatch를 사용하여 액션을 업데이트합니다. 

 

### thunk 문법
```sh
# redux-thunk 설치
npm i redux-thunk
```

```js

// store.js
import { createStore, applyMiddleware } from 'redux'; // 저장소 생성
import thunk from 'redux-thunk'
import reducer from './reducer' 

// 중간에 미들웨어(thunk) 추가
// 내부 로직의 미들웨어를 추가하기 위해서 스토어 생성할때 매개변수로 미들웨어를 전달

const store = createStore(reducer, applyMiddleware(thunk))

// applyMiddleware 내부에는 dispatch, getState 객체가 들어있다.
// 중간에 dispatch를 호출하면 실행될 미들웨어를 추가
applyMiddleware({dispatch, getState} => 
    action =>
    (dispatch, getState) =>{ 
})

// action create 함수
// userAction.js
import axios from 'axios';

// 유저의 프로필 정보를 요청하는 로직
// getUserAction (nick) 매개변수로 받는다
// 매개변수를 받는 이유는 
// 함수인데 함수값을 반환
export const getUserAction = (nick) => {
    return async (dispatch, getState) => { // 여기서 비동기 로직 처리
        const { data } = await axios.get(`http://localhost:4000/
        userinfo?nick=${nick}`) // 비동기 요청 후 아래 코드 실행
        // 전역상태 업데이트
        dispatch({type : "USERINFO", payload : data})
    } 
    // 반환을 하는데 익명함수로 반환
} 

// 컴포넌트에서 호출
import { useDispatch } from 'react-redux'
import { getUserAction } from './Actions/userAction.js';

const App = () => {
    const dispatch = useDispatch();

    const handler = () => {
        dispatch(getUserAction("suho"))

        const dispatch = (action) => {
            if(typeof action === "object") {
                // 타입 검사후 -> 객체면
                // 상태 업데이트 리듀서가 호출
                // 반환받은 값을 state에 업데이트

            } else if(typeof action === "function") {
                action(dispatch, getState)
                // 타입 검사후 -> 함수면
                // action이 실행되면서
                // dispatch와 getState를 매개변수로 전달해서 또 다른 dispatch를 비동기적으로 처리
            }
        }
    }

    return (<button>프로필 조회</button>)
}

 

 

1-5. redux-thunk의 목적

1. API의 로직을 비동기적으로 호출한 이후에 Store 업데이트
2. 액션 생성자 함수를 미들웨어로 추가해서 실행
3. 비동기로 로직과 동기 로직의 구분을 지어서 관리할 수 있다.

 

1-6. redux-thunk를 사용한 Todo-List 실습 

간단한 폴더 구조를 이렇게 나눠봤습니다.

### Todo List 만들어보자 실습
```sh
## 프론트엔드 모듈 설치
npm i redux react-redux axios redux-thunk styled-components

##  백엔드 모듈 설치
npm i express cors mysql2 sequelize

## 폴더 구조
src 
    -- Api # api 요청 로직의 코드 내용
        -- todo.js
    -- Actions # 액션 생성자 함수
        -- todoActions.js
    -- Reducers # 리듀서 함수
        -- todoReducers.js  
    -- Store # redux 스토어 저장소 초기화
        -- index.js 
    -- Components # 컴포넌트
        -- Atoms (원자)
        -- Molecules (분자)
        -- Organisms (유기체)
        -- Pages (레이아웃)
app.js
```

 

 

결론

 

Redux는 비동기 작업을 직접 처리할 수 없어 한계가 있습니다. 이 문제를 해결하기 위해 redux-thunk는 액션 생성자에서 함수를 반환해 비동기 로직을 처리하게 합니다. 그 결과, 비동기 요청 → 응답 → 상태 업데이트 흐름을 자연스럽고 유연하게 구현할 수 있습니다.

LIST