[Redux] redux-thunk

임홍원·2023년 11월 29일
1

Redux

목록 보기
4/4
post-thumbnail

Thunk가 뭔데?

Thunk는 프로그래밍에서 작업을 지연시키는 함수이다. 로직을 바로 실행시키지 않고 나중에 실행시킨다.
Thunk는 리덕스 앱에서 비동기 로직을 작성하는 표준 접근 방식이다.

Thunk를 사용하는 이유

ReduxReducer는 사이드 이펙트를 포함해선 안된다. 하지만 실제 어플리케이션에서 사이드이펙트를 발생시키는 로직을 필요로한다. Thunk는 이러한 사이드이펙트를 담아두는 역할을 한다. 예를들면 async 요청같은 경우가 있다.

Redux Middleware

Redux의 모든과정은 동기적으로 발생한다. 또한 ReduxReducer에는 비동기 로직이 존재할 수 없기 때문에 미들웨어를 사용한다. 아래는 Redux 미들웨어 동작원리에 대한 그림이다.

대표적으로 redux-thunk, redux-saga가 존재한다.

Redux-Thunk 사용방법

설치

npm install redux-thunk

Thunk 만들기

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

const initialState = {
	todos: [],
	isLoading: false,
	isError: false,
	error: null,
};

export const __getTodos = createAsyncThunk(
	'getTodos',
	async (payload, thunkAPI) => {
		try {
			const res = await axios.get('http://localhost:4000/todos');
            console.log(res.data)
			return thunkAPI.fulfillWithValue(res.data);
		} catch (error) {
			return thunkAPI.rejectWithValue(error);
		}
	}
);

export const todosSlice = createSlice({
	name: 'todos',
	initialState,
	reducers: {},
	extraReducers: {
        [__getTodos.pending]: (state, action) => {
            // 진행중
            state.isLoading = true;
            state.isError = false;
        },
		[__getTodos.fulfilled]: (state, action) => {
            // 성공시
			state.isLoading = false;
            state.isError = false;
            state.todos = action.payload
		},
        [__getTodos.rejected]: (state, action) => {
            // 성공시
			state.isLoading = false;
            state.isError = true;
            state.error = action.payload
		},
	},
});

export const {} = todosSlice.actions;
export default todosSlice.reducer;

createAsyncThunk

export const __getTodos = createAsyncThunk(
	'getTodos',
	async (payload, thunkAPI) => {
		try {
			const res = await axios.get('http://localhost:4000/todos');
            console.log(res.data)
			return thunkAPI.fulfillWithValue(res.data);
		} catch (error) {
			return thunkAPI.rejectWithValue(error);
		}
	}
);
  • 액션 타입 문자열, 프로미스를 반환하는 비동기함수, 추가 옵션 순서대로 인자를 받음
  • 입력받은 액션 타입 문자열을 기반으로 프로미스 라이프사이클 액션 타입을 생성하고, thunk action creator를 반환함
  • thunk action creator: 프로미스 콜백을 실행하고 프로미스를 기반으로 라이프사이클 액션을 디스패치한다.
  • 리듀서를 생성해주는 기능은 없기 때문에 액션들을 처리할 로직을 직접 작성해야 한다.

createAsyncThunk는 결과에 상관없이 무조건 이행된 프로미스를 반환한다.
따라서 오류처리는 별도로 해주어야 한다.

컴포넌트 내에서 하고 싶다면 리턴할 때에 thunkAPI에 존재하던 fulfillWithValuerejectWithValue의 호출결과를 리턴해주면 컴포넌트에서 해당 액션 객체의 메타데이터를 사용하는 것이 가능하다.

slice

export const todosSlice = createSlice({
	name: 'todos',
	initialState,
	reducers: {},
	extraReducers: {
        [__getTodos.pending]: (state, action) => {
            // 진행중
            state.isLoading = true;
            state.isError = false;
        },
		[__getTodos.fulfilled]: (state, action) => {
            // 성공시
			state.isLoading = false;
            state.isError = false;
            state.todos = action.payload
		},
        [__getTodos.rejected]: (state, action) => {
            // 실패시
			state.isLoading = false;
            state.isError = true;
            state.error = action.payload
		},
	},
});

reducers 는 자동으로 action creator를 생성하지만, extraReducers 는 action creator를 생성하지못한다.extraReducers 프로퍼티를 사용하는 경우는 비동기를위해 createAsyncThunk를 사용하여 정의된 액션함수를 사용하거나, 다른 slice에서 정의된 액션함수를 사용하는 경우이다.

useDispatch, useSelector

//App.jsx

import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import './App.css';
import { __getTodos } from './redux/modules/todoSlice';

function App() {
	const dispatch = useDispatch();
	const { todos, isLoading, isError } = useSelector((state) => state.todos);

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

	if (isLoading) {
		<div>로딩중입니다....</div>;
	}
	return (
		<div> {
            todos.map((item) => {
                return <div key={item.id}>
                    {item.id} : {item.title}
                </div>
            })}
		</div>
	);
}

export default App;

useDispatchuseSelector는 똑같이 사용하면 된다.

Reference : https://ko.redux.js.org/usage/writing-logic-thunks/

1개의 댓글

comment-user-thumbnail
2023년 11월 29일

따봉👍🏻👍🏻👍🏻👍🏻👍🏻

답글 달기