홈으로

[Architecture] Flux와 Redux에 대한 이해

2020년 01월 21일

MVC에서 Flux로

페이스북이 자사 시스템을 구현하면서 기존의 MVC 아키텍쳐는 양방향 데이터흐름(Bi-directional data flow) 을 가지고 있기 때문에 기능을 추가하면 추가할 수록 그 복잡성이 기하급수적으로 증가함을 느꼈다고 한다. 여기 에서 원문을 확인할 수 있는데, 자사가 적용한 MVC를 설명한 것에 대해 많은 개발자들이 논쟁을 하였다. 전통적인 MVC와 그들이 새로 개발한 Flux의 구조가 비슷하다는 것이며 페이스북이 MVC를 잘못 사용했다는 것이다. 이 논의에 대해 어떤 점이 정말 맞는지는 아직 잘 이해가 안되지만 MVC 아키텍쳐를 정의하는 여러가지 의견들이 있고 페이스북이 Flux라는 아키텍쳐를 새로 개발한 이유는 그들이 유지하는 시스템의 복잡성 때문이라는 것이다. 이 점을 인지하고 Flux 아키텍쳐를 보도록 하자.

Flux

양방향 데이터 흐름 때문에 복잡성이 생겼으므로 이를 단방향 데이터 흐름으로 만들어낸 아키텍쳐이다. 다음과 같은 구성원으로 이루어진다.

  • 액션 생성자(Action creator)

    • 액션이란 어떤 행위인지와 그 행위로부터 넘겨받은 값들을 가진 하나의 객체를 말한다. 따라서 어떤 액션인지를 가리키는 type 과 넘겨받은 값인 payload 를 가진다. 액션 생성자는 기존 상태를 변경하기 위한 액션의 생성을 담당하며 해당 액션을 생성해서 디스패쳐에 넘겨준다.
  • 디스패쳐(Dispatcher)

    • 디스패쳐는 모든 액션들을 받아서 의존성을 적절히 처리해준 다음 모든 스토어에게 넘긴다. 여기서 중요한 점은 모든 스토어가 모든 액션을 받는다는 것이다.
  • 스토어(Store)

    • 스토어는 모든 액션을 받아서 자신에게 적합한 액션이 어떤 건지 필터링한다. 이후 상태값을 변경하고 자신에게 연결된 컨트롤러 뷰에게 상태가 변화되었음을 알린다.
  • 컨트롤러 뷰(Controller View)와 뷰(View)

    • 여기서 컨트롤러 뷰는 전체적으로 화면에 나타는 자식 뷰들과 스토어를 연결하는 매개체이다. 자식 뷰들은 컨트롤러 뷰에게 변화된 상태를 받고 그 상태에 따라 다시 렌더링이 된다.

Redux

Dan Abromov가 Flux를 개선한 아키텍쳐로 핫 리로딩(Hot Reloading)과 시간여행 디버깅(Time-travel debugging)을 지원하는 개발자 도구가 구현되어있다. 구성원들은 Flux와 비슷하지만 리듀서(Reducer)를 추가해서 상태변경의 개념자체를 바꿔버렸다.

  • 액션 생성자(Action creator)

    • 액션 생성자는 사용자가 요청한 액션을 만들어서 포맷에 맞게 돌려준다.
  • 스토어(Store)

    • Flux에선 다수의 스토어를 가질 수 있지만 Redux는 단 하나의 스토어를 가진다. 대신에 상태 트리(State tree) 라고 불리는 상태값을 유지한다.
  • 리듀서(Reducer)

    • 디스패쳐가 없는 대신 리듀서가 상태변화로직을 담당한다. 리듀서는 전체 리듀서를 관리하는 루트 리듀서와 하위의 서브 리듀서로 나뉜다. 루트 리듀서는 상태 객체의 키(key)를 기준으로 조각조각 나누어서 서브 리듀서에게 보낸다.
    • 서브 리듀서는 이전 상태를 변경하지 않고 복사해서 변경한다. 이렇게 상태 객체를 업데이트 시키고 이를 루트 리듀서에게 돌려준다. 이것이 바로 Redux의 키 아이디어이다.
    • 루트 리듀서는 서브 리듀서들로 받은 상태 객체들을 취합해서 스토어로 보낸다.
  • 뷰 레이어 바인딩(View-Layer binding)

    • 스토어와 뷰를 연결하기 위한 것으로 뷰에서 스토어의 상태 값들에 접근하기 위해 필요하다. 공급 컴포넌트(Provider Component)를 통해서 스토어가 뷰에 상태를 공급하며 뷰에선 특정 함수(예를 들면 connect )를 통해서 스토어에 연결된다.
    • 이건 구성원이라기 보단 필요한 작업이라고 할 수 있다.

예시를 통한 이해

2개의 카운터가 있다고 해보자. 하나는 1씩 증가/감소 시키고 다른 하나는 2씩 증가/감소시킨다. 이를 redux로 구현하면 다음과 같이 구현할 수 있다.

  • 각각의 액션 및 액션 생성자를 정의한다.
  • 각각의 서브 리듀서를 정의한다.
  • 서브 리듀서를 루트 리듀서로 합친다.
  • 루트 리듀서를 스토어에 등록해서 스토어를 생성한다.
  • 공급 컴포넌트로 스토어의 상태를 뷰에 공급한다.
  • 뷰에서 상태값을 사용할 때 스토어에 연결하여 사용한다.

리액트에서 이를 구현하기 위해선 Redux의 개념을 담고 있는 redux 와 리액트에서 Redux를 더욱 용이하게 사용할 수 있도록 만들어주는 react-redux 패키지를 사용하면 된다. 아래 링크를 통해서 어떻게 동작하는지 보자.

Edit redux example

마무리

지금까지 Flux와 Redux에 대해 알아보았는데 프로젝트의 크기가 크지 않고 상태값이 많지 않다면 Context API와 useReducer와 같은 리액트의 기능을 조합해서 사용할 수도 있을 것이다. 하지만 프로젝트의 크기가 점점 커지고 그 복잡성이 기하급수적으로 늘어나게 될 것 같다면 Redux를 사용해서 상태관리를 하는 것이 프로젝트 관리에 훨씬 용이할 것이다.

Loading script...