Action은 무슨 일이 일어났는지를 기술하는 일반 객체이고, reducer는 현재 state와 action을 받아 다음 state를 반환하는 순수 함수입니다. 둘이 함께 예측 가능한 state 전이를 구현합니다.
Action — 이벤트를 기술
{ : , : { : , : } }
{ : , : }
Action은 무언가를 하지 않습니다. 이벤트에 대한 선언적 기술입니다. 과거 시제 사실("added", "toggled")로 이름 짓는 것은 무슨 일이 일어났는지를 기록한다는 것을 반영합니다.
function todosReducer(state = [], action) {
switch (action.type) {
case "todos/added":
return [...state, action.payload]; // 새 배열
case "todos/toggled":
return state.map(t => // 새 배열, 변경된 것은 새 객체
t.id === action.payload ? { ...t, done: !t.done } : t
);
default:
return state; // 알 수 없는 action → 변경 없음
}
}
reducer의 시그니처는 (state, action) => newState입니다. 입력을 변경하지 않고 항상 새로운 state 객체/배열을(immutable하게) 반환해야 합니다.
순수 함수는 (1) 같은 입력에 대해 같은 출력을 반환하고, (2) 부수 효과가 없습니다. reducer는 두 규칙을 모두 따라야 합니다:
// ❌ 순수하지 않음 — 모든 것을 망가뜨림
function badReducer(state, action) {
state.value++; // ❌ 입력을 변경(변경 감지, 타임 트래블 깨짐)
fetch("/api/log"); // ❌ 부수 효과(비결정적, 테스트 불가)
return { value: Math.random() }; // ❌ 비결정적 출력
}
순수성은 Redux의 대표적 기능을 가능하게 합니다:
✓ 예측 가능성 — 같은 state + action은 항상 같은 결과를 줌
✓ 타임 트래블 / 재생 — action을 재실행하여 어떤 state든 재현 가능
✓ 테스트 용이 — reducer(state, action)을 호출하고 단언하기만 하면 됨; mock 불필요
✓ 변경 감지 — 새 참조를 반환하면 UI가 변경을 감지할 수 있음
부수 효과(API 호출, 로깅, 난수)는 reducer가 아니라 미들웨어(thunk/saga)나 effect에 속합니다.
action/reducer 모델은 Redux 스타일 state management의 핵심이며, 그것이 디버깅과 테스트가 그토록 쉬운 이유입니다.
순수성 요구는 임의의 것이 아닙니다. 타임 트래블 디버깅, action 재생, 손쉬운 단위 테스트를 가능하게 만드는 것이며, 부수 효과가 다른 곳에 있어야 하는 이유입니다.
이 순수 함수 기반의 immutable 갱신 패턴은 Redux, NgRx, useReducer 등에서 반복됩니다 — 이를 이해하는 것(그리고 reducer를 순수하게 유지하는 규율)이 예측 가능한 state의 근본입니다.
주니어부터 시니어까지 상세한 답변이 포함된 IT 면접 질문 라이브러리.
후원하기