Flux 패턴이란 ?

김세빈·2025년 5월 11일

CS

목록 보기
15/22

Flux 패턴이란? 복잡한 상태 관리를 단방향으로 해결한다

웹 애플리케이션이 복잡해지면 상태(state) 관리가 점점 어려워진다. 특히 MVC 패턴에서는 ModelView 사이의 관계가 많아질수록 데이터 흐름이 꼬이고, 상태 추적이 어려워지는 문제에 직면하게 된다.

이러한 문제를 해결하기 위해 Facebook에서 제안한 아키텍처가 바로 Flux 패턴이다.


Flux 패턴이란?

Flux는 단방향 데이터 흐름을 기반으로 상태를 예측 가능하게 관리하는 아키텍처 패턴이다. MVC처럼 컴포넌트가 서로 참조하는 구조가 아니라, 명확한 흐름을 가진 파이프라인 구조를 지닌다.

Flux의 핵심 구성은 아래와 같다:

Action → Dispatcher → Store → View

Flux의 구조

1. Action

Action은 사용자의 이벤트(예: 버튼 클릭)나 API 응답처럼 애플리케이션에서 발생하는 모든 의도를 명시적으로 표현한다.

// action.ts
export const markAsRead = (messageId: number) => ({
  type: 'MARK_AS_READ',
  payload: { id: messageId },
});

2. Dispatcher

Dispatcher는 모든 액션을 중앙 집중식으로 처리하는 허브 역할을 한다. 어떤 Action이 발생했을 때, 어떤 Store에게 전달할지 결정한다.

// dispatcher.ts
import { Dispatcher } from 'flux';

const dispatcher = new Dispatcher();
export default dispatcher;

3. Store

Store상태(state)를 관리하는 계층이다. Action을 받아 내부 상태를 갱신한 뒤, View에 알려준다.

// messageStore.ts
import { EventEmitter } from 'events';
import dispatcher from './dispatcher';

class MessageStore extends EventEmitter {
  private messages: { id: number; read: boolean }[] = [];

  getMessages() {
    return this.messages;
  }

  handleActions(action: any) {
    switch (action.type) {
      case 'MARK_AS_READ':
        this.messages = this.messages.map((msg) =>
          msg.id === action.payload.id ? { ...msg, read: true } : msg
        );
        this.emit('change');
        break;
    }
  }
}

const messageStore = new MessageStore();
dispatcher.register(messageStore.handleActions.bind(messageStore));
export default messageStore;

4. View

ViewStore로부터 상태를 받아 화면을 렌더링한다. 단방향이기 때문에 View → Store로 직접 접근하지 않고, 오직 Action을 통해 상태를 변경한다.

// MessageList.tsx (React 기준)
import { useEffect, useState } from 'react';
import messageStore from './messageStore';
import { markAsRead } from './action';
import dispatcher from './dispatcher';

export function MessageList() {
  const [messages, setMessages] = useState(messageStore.getMessages());

  useEffect(() => {
    const onChange = () => setMessages(messageStore.getMessages());
    messageStore.on('change', onChange);
    return () => messageStore.removeListener('change', onChange);
  }, []);

  const handleClick = (id: number) => {
    dispatcher.dispatch(markAsRead(id));
  };

  return (
    <ul>
      {messages.map((msg) => (
        <li key={msg.id} onClick={() => handleClick(msg.id)}>
          {msg.read ? <s>읽음</s> : '읽지 않음'}
        </li>
      ))}
    </ul>
  );
}

왜 MVC가 아닌 Flux인가?

MVC는 규모가 작을 때는 효율적이지만, 애플리케이션이 커질수록 Model과 View 간의 의존성과 데이터 흐름이 복잡해지는 경향이 있다. 특히 "읽음 / 읽지 않음" 같은 상태 변경이 여러 컴포넌트에 영향을 줄 때, Model 간 동기화가 어렵고 버그 추적도 복잡해진다.

반면 Flux는 모든 데이터 흐름을 Action → Dispatcher → Store → View 순서로 고정하기 때문에 다음과 같은 장점이 생긴다.


Flux 패턴의 장점

  • 단방향 데이터 흐름: 어디에서 상태가 변경됐는지 추적하기 쉬움
  • 상태 일관성 향상: 하나의 Store에서만 관리하므로 동기화 문제 해결
  • 디버깅과 테스팅이 쉬움: 액션 기반으로 테스트 가능
  • 유지보수 용이: 컴포넌트 간 직접 참조가 없어 결합도가 낮음

Redux는 Flux 패턴의 진화 버전이다

많은 React 개발자들에게 친숙한 Redux는 사실 Flux 패턴을 따르는 라이브러리다.
Redux는 Flux의 복잡한 Dispatcher를 없애고 ReducerStore만으로 상태 관리를 단순화했다.

// Redux의 간단한 reducer 예시
function messageReducer(state = [], action) {
  switch (action.type) {
    case 'MARK_AS_READ':
      return state.map((msg) =>
        msg.id === action.payload.id ? { ...msg, read: true } : msg
      );
    default:
      return state;
  }
}

0개의 댓글