리액트 redux-thunk를 사용한 비동기 처리
리액트 애플리케이션에서 상태 관리를 하다 보면, 서버와의 비동기 통신이 필요한 상황이 자주 발생합니다. 이때 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의 동작
- 액션 생성자가 함수를 반환
- redux-thunk 미들웨어가 이 함수를 감지하고 실행
- 해당 함수 안에서 비동기 작업 실행
- 비동기 작업 완료 후, 결과를 바탕으로 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는 액션 생성자에서 함수를 반환해 비동기 로직을 처리하게 합니다. 그 결과, 비동기 요청 → 응답 → 상태 업데이트 흐름을 자연스럽고 유연하게 구현할 수 있습니다.