Allra Fintech

플럭스 패턴으로 보는 단방향 상태 흐름

상태 변경을 액션 기반으로 추적해 단방향으로 흘리는 이유와 운영 기준을 정리합니다.

학습 목표

  • 상태가 왜 단방향으로만 흘러야 하는지 설명할 수 있습니다.
  • view 이벤트 → action → reducer → state → view의 실제 처리 순서를 이해합니다.
  • “어느 컴포넌트가 언제 상태를 바꿨는가”를 추적 가능한 형태로 설계할 수 있습니다.

1) 왜 단방향 데이터 흐름이 도입되었나?

초기 UI 프레임워크(양방향 바인딩 방식)에서 자주 생긴 문제는 다음과 같습니다.

  • 한 상태를 여러 뷰가 동시에 변경하려고 해서 변경 주체가 불명확해짐
  • 상태 변경이 어디서 시작됐는지 추적이 어려워 버그 재현이 복잡해짐
  • 디버깅 시 “보기에 바뀐 값은 어디서 온 것인지”를 추적하기 어렵거나 느려짐

React의 공식 설계는 이 복잡도를 줄이기 위해 단방향 흐름을 기준으로 잡습니다.

  • 데이터는 위에서 아래로 내려감(props 기반 렌더)
  • 이벤트/의도는 아래에서 위로 전달되고, 실제 상태 변경은 명시적 경로로만 수행

즉, 상태가 중간에 임의로 새 생성을 하지 않고 “한 방향 + 한 번의 진입점”으로 흘러야 전체 동작이 예측 가능해집니다.

2) 상태 흐름을 Flux 관점으로 정렬하기

React 단일 뷰 단위에서도 Flux의 상태 개념을 그대로 대응해 볼 수 있습니다.

사용자 이벤트 -> Action -> Reducer -> State -> View
  • Action: 사용자의 의도와 변경 요청을 담은 메시지
    • 예: USER_SUBMIT_FORM, FETCH_SUCCESS, TOGGLE_DRAFT
  • Reducer: 이전 상태와 action을 받아 다음 상태를 계산
    • 순수 계산(부수효과 없음)에 집중
    • 라이브러리 이름을 떠나, setState에서 쓰는 상태 전이 함수를 포함한 개념
  • State: View가 소비할 단일 상태 소스
  • View: 새 상태를 바탕으로 UI 트리를 산출

Flux 패턴의 강점은 “누가 상태를 바꿨는지”가 로그처럼 추적된다는 점입니다.
액션이 없어도 상태 전이가 흩어져 있으면 추적성이 떨어지고, 책임 경계가 흐려집니다.

3) 한 방향 규칙(공식 철학과 맞닿는 기준)

React 공식 문서의 설계 기준을 적용하면, 다음 규칙이 됩니다.

  1. 상태의 소유권은 한 곳에 둔다.
  2. 상태 변경은 의도(action)로 시작한다.
  3. 상태 계산은 순수 전이 함수 형태로 분리한다.
  4. 하위 컴포넌트는 props와 이벤트 경계를 통해 동작한다.

이 규칙을 지키면 다음 결과가 생깁니다.

  • 특정 상태가 어떤 이벤트로 바뀌었는지 추적 가능
  • 렌더링 재현성 향상(동일 입력은 동일 출력)
  • 팀 단위로 상태 변경 동선 합의가 쉬워짐

4) 컴포넌트 구조에서의 책임 분리

4.1 화면 상태와 도메인 상태 구분

  • 화면 상태(local UI): 모달, 폼 드래프트, 탭, 입력 포커스
  • 서버 상태(remote): 원격 데이터, 캐시, 재요청 정책, 동기화 여부

둘을 같은 상태 집합에 섞으면 갱신 기준이 달라져 버그가 커집니다.

4.2 상태 변경 경로 예시

type FetchPostsState =
  | { phase: 'idle' }
  | { phase: 'loading'; query: string }
  | { phase: 'success'; data: Post[] }
  | { phase: 'error'; error: Error }

const [fetchState, setFetchState] = useState<FetchPostsState>({ phase: 'idle' })

const loadPosts = useCallback(async (query: string) => {
  setFetchState({ phase: 'loading', query })
  try {
    const nextPosts = await api.fetchPosts(query)
    setFetchState({ phase: 'success', data: nextPosts })
  } catch (error) {
    setFetchState({ phase: 'error', error: error instanceof Error ? error : new Error('unknown') })
  }
}, [])

이 방식은 구현 코드에서 dispatch를 직접 보지 않더라도,
내부적으로는 여전히 의도 → 상태 전이 → 새 상태의 단방향 경로를 따릅니다.

5) 운영 체크리스트

  • action 단위가 UI에서 수행할 동작을 충분히 설명하는가?
  • 상태 전이 함수(reducer/handler)가 부수효과가 아닌 상태 계산만 담당하는가?
  • 상태 소유권이 분산되지 않고 의사결정이 가능한 범위로 모여 있는가?
  • 화면 상태와 서버 상태가 분리되어 있고, 갱신 정책이 분명한가?
  • 동일 상태 변경이 여러 경로에서 같은 액션 경유 없이 발생하지 않는가?

6) 핵심 요약

  • 단방향 흐름은 “구조적 단순성”을 위해 도입된 핵심 규칙입니다.
  • 모든 상태 변경은 action/의도 → 상태 전이 함수 → state로 설명 가능해야 합니다.
  • React는 상태 변경을 렌더링 계산으로 연결하므로, 경로가 분명한 상태 모델이 유지보수성과 디버깅 효율을 높입니다.

8) 참고