Redux 미들웨어란?
Redux는 상태 관리 아키텍처로, 세 가지 핵심 요소인 스토어(store), 리듀서(reducer), 액션(action)으로 구성됩니다. 이 중 리듀서는 순수 함수여야 하므로, 외부 API 호출이나 비동기 작업 같은 사이드 이펙트를 직접 처리할 수 없습니다. 이러한 제약을 해결하기 위해 등장한 개념이 바로 미들웨어(middleware)입니다.
미들웨어는 액션이 디스패치된 후 리듀서가 이를 처리하기 전 단계에서 추가 로직을 삽입할 수 있도록 해줍니다. 즉, dispatch() 메서드의 동작을 확장하거나 래핑함으로써, 로깅, 비동기 작업 처리, 에러 추적 등의 기능을 구현할 수 있습니다.
미들웨어의 실행 흐름
미들웨어는 다음과 같은 흐름으로 작동합니다:
dispatch(action) → 미들웨어 체인 → store.dispatch() → reducer
미들웨어는 일종의 '중간 처리 파이프라인'처럼 동작하며, 여러 개를 연결하여 사용할 수 있습니다. 각 미들웨어는 다음 단계(next)로 넘기기 전에 자신의 작업을 수행하게 됩니다.
커스텀 로깅 미들웨어 작성 예제
다음은 상태 변경 전후의 값을 콘솔에 출력하는 간단한 로깅 미들웨어입니다:
const createLogger = (store) => (next) => (action) => {
console.group(`액션: ${action.type}`);
console.log('현재 상태', store.getState());
console.log('디스패치된 액션', action);
const result = next(action);
console.log('변경된 상태', store.getState());
console.groupEnd();
return result;
};
이 코드는 클로저 패턴을 활용해 store, next, action에 접근할 수 있도록 하며, 실제 디스패치 전후로 로그를 기록합니다.
미들웨어 적용 방법
미들웨어는 스토어 생성 시 applyMiddleware() 함수를 통해 등록됩니다:
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './reducers';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
const store = createStore(
rootReducer,
applyMiddleware(thunk, logger)
);
export default store;
redux-thunk: 비동기 액션 처리
기본적으로 Redux는 객체 형태의 액션만 처리합니다. 하지만 redux-thunk를 사용하면 액션 생성자가 함수를 반환할 수 있게 되어, 비동기 작업을 포함한 복잡한 로직을 처리할 수 있습니다.
동작 원리
thunk 미들웨어는 들어오는 액션이 함수인지 확인하고, 만약 함수라면 dispatch와 getState를 인자로 호출합니다:
const createThunk = ({ dispatch, getState }) => (next) => (action) => {
if (typeof action === 'function') {
return action(dispatch, getState);
}
return next(action);
};
사용 예시
예를 들어, 1초 후 상태를 업데이트하는 비동기 액션은 다음과 같이 정의할 수 있습니다:
// actions/todos.js
export const clearCompletedAsync = () => {
return (dispatch, getState) => {
setTimeout(() => {
dispatch({ type: 'TODOS_CLEAR_COMPLETED' });
}, 1000);
};
};
// 컴포넌트 내부
dispatch(clearCompletedAsync());
redux-logger: 상태 변화 기록
redux-logger는 모든 액션과 그에 따른 상태 변화를 콘솔에 자세히 출력해주는 미들웨어입니다. 개발 과정에서 상태 흐름을 추적하고 버그를 디버깅하는 데 매우 유용합니다.
import logger from 'redux-logger';
const store = createStore(
rootReducer,
applyMiddleware(logger)
);
Redux DevTools Extension: 고급 디버깅
브라우저 확장 프로그램인 Redux DevTools를 사용하면 실시간으로 상태 트리 확인, 액션 타임라인 재생, 상태 스냅샷 저장 등의 강력한 디버깅 기능을 사용할 수 있습니다.
설치 및 설정
- 크롬 웹 스토어에서 "Redux DevTools" 확장 프로그램 설치
- 패키지 설치:
yarn add redux-devtools-extension - 스토어 생성 시 통합:
import { composeWithDevTools } from 'redux-devtools-extension';
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(thunk, logger))
);
이렇게 설정하면 개발자 도구에서 Redux 탭을 통해 상태 변화를 시각적으로 모니터링할 수 있습니다.
기타 미들웨어 소개
- redux-saga: 제너레이터 기반으로 복잡한 사이드 이펙트를 관리. 비동기 로직을 별도 파일로 분리해 유지보수성을 높입니다.
- redux-promise: 프로미스 기반 액션을 지원하여
payload.then()형식으로 처리 가능.
각 미들웨어는 사용 사례에 따라 선택됩니다. thunk는 간단한 비동기 작업에 적합하고, saga는 복잡한 워크플로우나 취소 가능한 요청에 더 적합합니다.