[번역] React에서 reducer를 실제로 호출하는 주체는 누구일까?
Soshy·
React의 useReducer 훅을 배우다 보면 흔히 이런 의문이 생긴다.
"dispatch를 호출하면, reducer는 누가 실행하는 걸까? 내가 직접 실행하는 건가, 아니면 React가 내부적으로 처리하는 건가?"
단순해 보이는 질문이지만, 이 답을 이해하면 React의 상태 시스템이 내부적으로 어떻게 동작하는지 이해하는 문이 열린다.
dispatch를 호출하는 순간 어떤 일이 벌어지나?
코드를 다음과 같이 작성한다면, 당신은 reducer를 직접 호출한 것이 아니다.
dispatch({ type: "increment" })
더 중요한 점은 dispatch도 reducer를 직접 실행하지 않는다는 것이다.
실제로 일어나는 일은 다음과 같다.
- React가 액션을 큐에 등록한다.
- React가 해당 컴포넌트를 곧 리렌더링할 대상으로 표시한다.
- 다음 렌더 사이클에서 React는 큐에 쌓인 모든 액션을 처리한다.
- 바로 이 순간, React가 reducer를 호출한다:
reducer(currentState, action) - React는 reducer의 반환값을 새로운 상태로 저장한다.
- React가 컴포넌트를 리렌더링한다.
reducer를 호출하는 주체는 React다. 당신이 아니다.
React는 왜 reducer를 직접 호출하게 두지 않을까?
만약 React가 reducer를 직접 실행하도록 허용한다면,
state가 React의 제어권 밖으로 벗어나게 된다- 업데이트 배칭이 깨진다
- 리렌더링이 예측 불가능해진다
- 동시성(Concurrency) 및 스케줄링이 작동하지 않는다
- UI 안정성이 무너진다
React는 의도적으로 모든 상태 업데이트가 하나의 제어된 흐름을 통과하도록 강제한다:
dispatch → reducer → 새로운 state → 리렌더링
이 구조가 일관성, 예측 가능성, 렌더링 효율성을 보장한다.
dispatch가 실제로 하는 일은?
개념적으로 dispatch는 세 가지 작업을 수행한다:
1. 액션을 큐에 등록한다
React는 액션을 기록하고 내부 업데이트 큐에 추가한다.
2. 리렌더링을 예약한다
React는 해당 컴포넌트를 곧 리렌더링해야 할 대상으로 표시한다.
3. reducer 실행 시점을 React에게 위임한다
React는 reducer를 즉시 실행하지 않고, 렌더 단계에서 실행한다.
이것이 바로 dispatch 직후에 상태를 로깅해도 업데이트된 값이 보이지 않는 이유이다. reducer가 아직 실행되지 않았기 때문이다.
그렇다면 reducer는 정확히 무엇인가?
reducer는 순수 함수(pure function) 다.
function reducer(state, action) {
switch (action.type) {
case "increment":
return { ...state, count: state.count + 1 }
default:
return state
}
}
reducer는 순수하기 때문에,
- 타이밍에 의존하지 않는다
- 사이드 이펙트가 없다
- 출력이 예측 가능하다
React는 새로운 UI를 계산하기 위해 필요할 때마다(심지어 여러 번이라도) reducer를 안전하게 호출할 수 있다.
이 설계가 React가 동시 렌더링(Concurrent Rendering), 배칭(Batching), 예측 가능한 상태 관리를 지원하는 근간이다.
이걸 이해하면 뭐가 달라지나?
reducer를 누가 호출하는지 알면, 헷갈렸던 동작들이 이해되기 시작한다.
1. 상태 업데이트는 즉각적이지 않다
React는 렌더 단계가 될 때까지 reducer 실행을 기다린다.
2. 여러 번의 dispatch가 하나의 렌더로 이어질 수 있다
React가 배칭 처리하기 때문이다.
3. dispatch 직후 로그에는 이전 값이 찍힌다
reducer가 아직 실행되지 않았기 때문이다.
4. 상태는 항상 일관되고 예측 가능하다
React가 업데이트 시점을 중앙에서 통제하기 때문이다.
유용한 멘탈 모델
useReducer를 3단계 파이프라인으로 떠올려 보자.
[ dispatch ] → [ 액션 큐 ] → [ React가 reducer 실행 ]
당신의 역할은 첫 번째 단계에서 끝난다.
나머지는 React가 처리한다.