- 발행일
[ZBF] 7주차 보충 : Redux 미들웨어로 주로 사용하는 두 가지는 Redux Thunk와 Redux Saga
[ZBF] 7주차 보충 : Redux 미들웨어로 주로 사용하는 두 가지는 Redux Thunk와 Redux Saga
이 글은 네이버 블로그에 2024년 6월 30일에 올렸던 것을 그대로 옮겨온 것입니다.
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
// 초기 상태
const initialState = {
data: [],
loading: false,
error: null,
};
// 리듀서 함수
function dataReducer(state = initialState, action) {
switch (action.type) {
case 'FETCH_DATA_REQUEST':
return { ...state, loading: true, error: null };
case 'FETCH_DATA_SUCCESS':
return { ...state, loading: false, data: action.payload };
case 'FETCH_DATA_FAILURE':
return { ...state, loading: false, error: action.error };
default:
return state;
}
}
// 비동기 액션 크리에이터
function fetchData() {
return (dispatch) => {
dispatch({ type: 'FETCH_DATA_REQUEST' });
fetch('https://api.example.com/data')
.then((response) => response.json())
.then((data) => dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data }))
.catch((error) => dispatch({ type: 'FETCH_DATA_FAILURE', error }));
};
}
// 스토어 생성
const store = createStore(dataReducer, applyMiddleware(thunk));
// 비동기 액션 디스패치
store.dispatch(fetchData());
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { takeEvery, call, put } from 'redux-saga/effects';
// 초기 상태
const initialState = {
data: [],
loading: false,
error: null,
};
// 리듀서 함수
function dataReducer(state = initialState, action) {
switch (action.type) {
case 'FETCH_DATA_REQUEST':
return { ...state, loading: true, error: null };
case 'FETCH_DATA_SUCCESS':
return { ...state, loading: false, data: action.payload };
case 'FETCH_DATA_FAILURE':
return { ...state, loading: false, error: action.error };
default:
return state;
}
}
// Saga 제너레이터 함수
function* fetchDataSaga() {
try {
yield put({ type: 'FETCH_DATA_REQUEST' });
const response = yield call(fetch, 'https://api.example.com/data');
const data = yield response.json();
yield put({ type: 'FETCH_DATA_SUCCESS', payload: data });
} catch (error) {
yield put({ type: 'FETCH_DATA_FAILURE', error });
}
}
// Saga 감시자 함수
function* watchFetchDataSaga() {
yield takeEvery('FETCH_DATA_SAGA', fetchDataSaga);
}
// Saga 미들웨어 생성
const sagaMiddleware = createSagaMiddleware();
const store = createStore(dataReducer, applyMiddleware(sagaMiddleware));
// Saga 실행
sagaMiddleware.run(watchFetchDataSaga);
// 비동기 액션 디스패치
store.dispatch({ type: 'FETCH_DATA_SAGA' });
Redux Thunk
설명
Redux Thunk는 Redux에서 비동기 작업을 처리하기 위한 간단한 미들웨어입니다. Thunk를 사용하면 액션 크리에이터가 함수(Thunk)를 반환할 수 있으며, 이 함수는 디스패치와 상태를 인자로 받아 비동기 작업을 수행할 수 있습니다.
장점
- 간단한 사용법: 설정과 사용이 간단하여 빠르게 적용할 수 있습니다.
- 경량성: 작은 프로젝트나 간단한 비동기 작업에 적합합니다.
- 직관적: 자바스크립트 함수의 형태로 비동기 로직을 작성할 수 있어 직관적입니다.
단점
- 복잡한 비동기 로직 관리 어려움: 복잡한 비동기 흐름을 관리하기에는 코드가 복잡해질 수 있습니다.
- 코드 가독성 저하: 비동기 로직이 많아지면 코드의 가독성이 떨어질 수 있습니다.
- 테스트 어려움: 비동기 함수 내에서 상태와 디스패치를 다루기 때문에 테스트가 어려울 수 있습니다.
사용 상황
- 간단한 비동기 요청: 단순한 API 호출이나 타이머 등의 작업에 적합합니다.
- 작은 프로젝트: 프로젝트가 작거나 비동기 로직이 복잡하지 않을 때 사용하기 좋습니다.
- 빠른 설정 필요: 빠르게 비동기 작업을 처리해야 하는 경우 적합합니다.
Redux Saga
설명
Redux Saga는 Redux 애플리케이션에서 복잡한 비동기 작업을 관리하기 위한 강력한 미들웨어입니다. 제너레이터 함수를 사용하여 비동기 작업을 순차적으로 처리하거나 병렬로 처리할 수 있습니다. 이는 비동기 흐름을 더 구조적으로 관리할 수 있게 해줍니다.
장점
- 복잡한 비동기 로직 관리: 복잡한 비동기 흐름을 관리하기에 적합합니다.
- 제너레이터 함수 사용: 제너레이터 함수를 사용하여 코드를 더 명확하고 유지보수하기 쉽게 만듭니다.
- 고급 비동기 패턴 지원: 에러 핸들링, 폴링, 캐싱 등 고급 비동기 패턴을 쉽게 구현할 수 있습니다.
- 테스트 용이성: 비동기 로직을 테스트하기 쉬운 구조를 제공합니다.
단점
- 설정과 사용법의 복잡성: 설정과 사용법이 상대적으로 복잡하여 학습 곡선이 있습니다.
- 오버헤드: 작은 프로젝트에서는 과도할 수 있습니다.
- 초기 설정 시간: 초기 설정에 시간이 걸릴 수 있습니다.
사용 상황
- 복잡한 비동기 로직: 복잡한 비동기 작업을 많이 다루는 프로젝트에 적합합니다.
- 비동기 작업의 순서 중요: 비동기 작업의 순서가 중요하거나 여러 비동기 작업을 결합해야 하는 경우에 적합합니다.
- 고급 비동기 패턴 필요: 에러 핸들링, 캐싱, 폴링 등의 고급 비동기 패턴이 필요한 경우 사용하기 좋습니다.
제너레이터 함수는 ES6에서 도입된 특별한 종류의 함수로, 호출되면 하나 이상의 값을 순차적으로 반환할 수 있습니다. 제너레이터 함수는 일반 함수와 다르게 실행을 일시 중지하고 다시 시작할 수 있습니다. 이를 통해 비동기 작업을 보다 쉽게 처리할 수 있습니다.
제너레이터 함수는 function* 키워드를 사용하여 정의합니다. 그리고 함수 내부에서 yield 키워드를 사용하여 값을 반환하고, 함수의 실행을 일시 중지할 수 있습니다. yield는 함수의 실행을 중단하고, 호출자에게 제어를 반환하는 역할을 합니다.
제너레이터 함수와 일반 함수는 몇 가지 중요한 차이점이 있습니다:
정의 방식:
일반 함수: 일반적으로 function 키워드를 사용하여 정의합니다.
제너레이터 함수: function* 키워드를 사용하여 정의합니다.
실행 방식:
일반 함수: 호출되면 함수 내부의 모든 코드가 한 번에 실행됩니다.
제너레이터 함수: 호출되면 실행이 일시 중지될 수 있으며, yield 키워드를 사용하여 제어를 호출자에게 반환합니다. 필요할 때 next() 메서드를 호출하여 실행을 재개할 수 있습니다.
반환 값:
일반 함수: 단일 값을 반환합니다.
제너레이터 함수: 여러 값을 순차적으로 반환할 수 있으며, yield 키워드를 통해 각 값을 반환합니다. next() 메서드가 호출될 때마다 다음 yield 지점까지 실행됩니다.
상태 유지:
일반 함수: 호출이 완료되면 상태를 유지하지 않습니다.
제너레이터 함수: yield 지점에서 실행을 중지하고 상태를 유지합니다. 나중에 next() 메서드를 호출하면 중지된 상태에서 실행이 재개됩니다.