본문으로 바로가기

[React] Flux 패턴과 Elm 아키텍처

category 1. 웹개발/1_1_5 React JS 2024. 5. 18. 12:18

 

 

Flux 패턴의 등장 배경

아래 그림에서 보실 수 있듯이 기존의 MVC 패턴은 상태를 변경하는데 추적하고 이해하기가 매우 어려운 상황이였습니다.

기준 MVC 패턴은 모델과 뷰가 많아질수록 복잡도가 증가

 

페이스북 팀은 이러한 문제의 원인을 양방향 데이터 바인딩으로 봤습니다. 뷰(HTML)가 모델(자바스크립트)을 변경할 수 있으며, 반대의 경우 모델도 뷰를 변경할 수 있습니다. 이는 코드를 작성하는 입장에서는 간단할 수 있지만 코드의 양이 많아지고 변경 시나리오가 복잡해질수록 관리가 어려워집니다. 페이스북 팀은 양방향이 아닌 단반향으로 데이터 흐름을 변경하는 것을 제안하는데 이것이 바로 Flux 패턴의 시작입니다. 

 

Flux 패턴

Flux의 기본적인 단방향 데이터 흐름

  • action: 어떠한 작업을 처리할 액션과 그 액션 발생 시 함께 포함시킬 데이터를 의미합니다. 액션 타입과 데이터를 각각 정의해 이를 디스패쳐로 보냅니다.
  • dispatcher: 액션을 스토어에 보내는 역할을 합니다. 콜백 함수 형태로 앞서 액션이 정의한 타입과 데이터를 모두 스토어에 보냅니다.
  • store: 여기에서 실제 상태에 따른 값과 상태를 변경할 수 있는 메서드를 가지고 있습니다. 액션의 타입에 따라 어떻게 이를 변경할지가 정의돼 있습니다.
  • view: 리액트의 컴포넌트에 해당하는 부분으로, 스토어에서 만들어진 데이터를 가져와 화면을 렌더링하는 역할을 합니다. 또한 뷰에서도 사용자의 입력이나 행위에 따라 상태를 업데이트하고자 할 수 있을 것입니다. 이 경우에는 다음 그림처럼 뷰에서 액션을 호출하는 구조로 구성됩니다. 

Flux 패턴에서 뷰 또한 액션을 호출할 수 있으며, 이후 프로세스는 동일합니다.

 

하지만, 이러한 Flux 패턴에도 불편함은 존재했습니다. 사용자의 입력(이벤트)에 따라 데이터를 갱신하고 화면을 어떻게 업데이트해야 하는지도 코드로 작성해야 하므로 코드의 양이 많아지고 개발자도 수고러워집니다. 그러나 데이터의 흐름은 모두 액션이라는 한 방향(단방향)으로 줄어들므로 데이터의 흐름을 추적하기 쉽고 코드를 이해하기가 한결 수월해집니다.

 

Redux의 등장

리액트와 단방향 데이터 흐름이 점점 두각을 드러내던 와중에 등장한 것이 바로 리덕스(Redux)입니다. 리덕스 또한 최초에는 이 Flux 구조를 구현하기 위해 만들어진 라이브러리 중 하나였습니다. 이에 한 가지 더 특별한 것은 여기에 Elm 아키텍쳐를 도입했다는 것입니다.

 

Elm은 웹페이지를 선언적으로 작성하기 위한 언어입니다. Elm 아키텍처의 핵심 요소는 바로 model, update, view입니다.

  • model: 애플리케이션의 상태를 의미합니다.
  • view: 모델을 표현하는 HTML을 말합니다.
  • update: 모델을 수정하는 방식을 말합니다.

즉, Elm은 Flux와 마찬가지로 데이터 흐름을 세 가지로 분류하고, 이를 단방향으로 강제해 웹 애플리케이션의 상태를 안정적으로 관리하고자 노력했습니다. 그리고 리덕스는 이 Elm 아키텍처의 영향을 받아 작성됐습니다.

 

리덕스는 하나의 상태 객체를 스토어에 저장해두고, 이 객체를 업데이트하는 작업을 디스패치해 업데이트를 수행합니다. 이러한 작업은 reducer 함수로 발생시킬 수 있는데, 이 함수의 실행은 웹 애플리케이션 상태에 대한 완전히 새로운 복사본을 반환한 다음, 애플리케이션에 이 새롭게 만들어진 상태를 전파하게 됩니다.

 

이러한 리덕스의 등장은 리액트 생태계에 많은 영향을 미치게 되었습니다. 하나의 글로벌 상태 객체를 통해 이 상태를 하위 컴포넌트에 전파할 수 있기 때문에 props를 깊이 전파해야 하는 이른바 props drilling 문제를 해결할 수 있었고, 스토어가 필요한 컴포넌트라면 단지 connect만 쓰면 스토어에 바로 접근할 수 있었습니다. Context API가 등장하기 전까지, 아니 지금까지도 리덕스는 리액트 상태 관리에서 빼놓고 이야기할 수 없는 중요한 축으로 자리잡았습니다.

 

그렇다로 리덕스가 마냥 편하기만 한 것은 아니었습니다. 단순히 하나의 상태를 바꾸고 싶어도 해야 할 일이 너무 많았습니다. 먼저 어떠한 액션인지 타입을 선언해야 하고, 이 액션을 수행할 creator 함수를 만들어야 합니다. 그리고 dispatcher와 selector도 필요하고, 새로운 상태가 어떻게 기존의 리듀서 내부에서 어떤 식으로 변경돼야 할지, 혹은 새로 만들어야 할지도 새로 정의했습니다. 한마디로, 하고자 하는 일에 비해 보일러플레이트가 너무 많다는 비판의 목소리가 있었습니다. 이는 리덕스가 처음 등장했을 때 받던 비판으로, 지금은 이러한 작업이 많이 간소화됐지만 아직까지도 작성해야할 코드가 많이 있긴 합니다.

 

저 또한 리덕스의 이러한 보일러플레이트 코드 때문에 개인 프로젝트 진행 당시 Recoil과 React Query로 마이그레이션한 경험도 있습니다. 하지만 아직까지도 리액트와 리덕스는 일종의 표준처럼 굳혀져있으므로 리덕스가 Flux 패턴과 Elm 아키텍처 구조로 작성되었다라는 것은 개발자가 알면 좋을 내용으로 생각됩니다. 

 

 

 

References

React Deep Dive

[React] react-redux 정리 및 예제

[React] React Query를 사용하는 이유 (vs Redux)

[React] Recoil + React Query를 도입한 이유