[Redux] redux-thunk

Dodam·2024년 1월 30일
0

[Redux]

목록 보기
10/11
post-thumbnail

redux-thunk

리덕스에서는 기본적으로 액션 객체를 디스패치 한다.
하지만 thunk 미들웨어를 사용하면 객체 대신 함수를 생성하는 액션 생성함수를 작성할 수 있게 해준다.

이러한 동작 방식을 활용하여 Redux에서 비동기적인 프로그래밍을 구현할 수 있다.

function increment() {
	return {
		type: INCREMENT_COUNTER
	};
}

예전에는 액션 생성함수에서 위와 같은 type을 가지는 객체를 생성해주었다면

function increment() {
	return {
		type: INCREMENT_COUNTER
	};
}

function incrementAsync() {
	return dispatch => {  // dispatch를 가지는 함수를 리턴한다.
		setTimeout(() => {
			// 1초 뒤 dispatch 한다.
			dispatch(increment());
		}, 1000);
	};
}

redux-thunk를 사용하면 위의 incrementAsync 같은 함수를 생성하는 액션 생성함수를 만들 수 있다.

함수를 dispatch 하는 thunk

만약, 리턴하는 함수에서 dispatch, getState를 파라미터로 받게 한다면
아래와 같이 스토어의 상태에도 접근할 수 있다.

따라서, 현재의 스토어 상태 값에 따라 액션이 dispatch 될 지, 무시될 지 정해줄 수 있다.

function incrementIfOdd() {
	return (dispatch, getState) => {
		const { counter } = getState();

		if (counter % 2 === 0 ) {
			return;
		}

		dispatch(increment());
	};
}

보통의 액션 생성자는 그냥 하나의 액션 객체를 생성할 뿐이지만,
redux-thunk를 통해 만든 액션 생성자는 그 내부에서 여러가지 작업을 할 수 있다.

예를 들면 네트워크 요청을 하거나, 스토어에 접근해서 state를 읽어오거나, 다른 액션을 디스패치 하는 등 액션을 여러 번 디스패치 할 수도 있다.

Redux-toolkit의 thunk를 이용하여 비동기 로직 처리하기

import axios from 'axios';
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'


// createAsyncThunk는 비동기 작업을 처리하는 액션(Action Creator)을 생성
// 첫 번째 인수로 타입을, 두 번째 인수로 액션이 실행됐을 때 처리되어야 할 작업을 함수로 전달
export const fetchData = createAsyncThunk('FETCH_DATA', async () => {
	try { 
				const response = await axios.get('http://localhost:8000')
		  return response.data;
		} catch (error) {
			console.error(error);
		}
});


// 비동기 작업의 3가지 상태 (pending, fulfilled, rejected)
export const rootReducer = createSlice({
	name: 'Data',
	initialState: { 
		data: [],
		status: 'Welcome'
	},
	reducers: {  // 동기적인 작업을 수행할 때 사용 (Redux-toolkit이 액션 생성자를 자동으로 생성해 줌)
		// omit reducer cases
	},
	extraReducers: (builder) => {  // 비동기적인 작업을 수행할 때 사용 (액션 생성자를 자동으로 만들어주지 못하기 때문에 extraReducers 안에 직접 정의함)
		builder
			.addCase(fetchData.pending, (state, action) => {
				// 데이터 통신 중일 때
				// state.status = 'Loading' 또는 다음과 같은 형태로 반환
				return {
					...state,
					status: 'Loading',
				}
			})
			.addCase(fetchData.fulfilled, (state, action) => {
				// 데이터 통신에 성공했을 때
				return {
					...state, 
					data: [ ...action.payload ],
					status: 'Completed',
				}
			})
			.addCase(fetchData.rejected, (state, action) => {
				// 데이터 통신에 실패했을 때
				return {
					...state,
					status: 'Failed',
				}
			})
		},
})

// app.ts
dispatch(fetchData())
profile
Good things take time

0개의 댓글