리덕스 개념을 정리하는 포스팅이다.
위 그림은 작년 말에 있었던 state of js에서의 리서치 결과인데 41.7%의 자바스크립트 개발자들이 데이터 형상 관리로 리덕스를 '사용한적이 있고 앞으로 다시 사용할 것'이라고 대답했다. GraphQL에 대한 관심이 뜨겁지만 현재 자바스크립트 생태계에서 형상 관리 기술로는 리덕스가 1위를 차지하고 있다.
리덕스가 등장하기 이전 프론트엔드에서 데이터 흐름(형상)을 관리하는 방식은 MVC 패턴이었다.
이미지 : http://aalmiray.github.io/griffon-patterns/
MVC 패턴의 큰 특징 중 하나가 '양방향 데이터 흐름'이다. 모델이 변경된다면 뷰 또한 변경되고, 사용자에 의해 뷰에서 변경이 일어난다면 모델 또한 변경된다. 이러한 양방향 데이터 흐름은 설계하기 간단하고 코드 작성하기 쉬운 장점이 있다. 하지만 애플케이션 규모가 커진다면 문제가 생긴다. 한 개의 모델이 여러 개의 뷰를 조작하고 한 개의 뷰가 여러 개의 모델을 조작한다면 데이터 흐름을 이해하기 힘들어진다. 버그를 찾기 어려워지고 데이터 흐름을 추적하는 데 많은 시간을 투자해야 한다.
2014년 페이스북에서 MVC 패턴으로 데이터 흐름을 관리하는 데 많은 어려움을 겪고 있었고 그의 대안으로 Flux라는 새로운 아키텍처 패턴을 개발하였다.
기존의 애플케이션과 달리 페이스북은 굉장히 많은 뷰와 모델이 필요로 하게 되었고 거기에 사용자와의 인터렉션 또한 기존 서비스보다 훨씬 많아졌다. 그로 인해서 많은 버그가 발생하게 되었고 수 많은 양방향의 데이터 흐름 때문에 버그를 수정하기도 힘들었다. 페이스북의 알람 정보가 제대로 업데이트 되지 않아 알람 표시가 계속 유지되는 문제가 대표적이다.
Flux는 MVC 패턴에서 겪은 복잡한 상황을 개선하는 것이 목적이었고 그 방법으로 '단방향 데이터 흐름' 을 적용한 것이다. View는 MVC 패턴과 달리 데이터를 변경시키지 않고 Action을 넘겨준다. Action은 반드시 Dispatcher를 지나게 되고 Dispatcher를 통해서 데이터 변경이 일어나고 View는 변경된 데이터를 Store를 통해서 전달 받는다. 이러한 단방향 데이터 흐름은 기존의 MVC 패턴에 있던 '상태의 전이'(뷰와 모델 사이의 데이터 변경이 연결된 수많은 곳으로 따라 변경되는 현상) 현상을 없애주고 '예측 가능하다' 는 특징을 갖는다.
2015년에는 Dan Abramov에 의해서 React + Flux의 구조에 'Reducer'를 결합한 'Redux'가 등장하게 된다.
Redux = (Red)ucer + Fl(ux)
Flux로 그 전의 겪어던 문제들을 충분히 해결했는데 왜 굳이 리덕스를 사용해야 할까? 이 질문에 Redux의 제작자 Dan Abramov가 직접 답해주었다.
1. 리듀서의 구성
2. 서버 랜더링
3. 좋은 개발자 경험
4. 간결성
이유에 대한 자세한 이야기는 원문 링크에서 확인할 것 why use Redux over Facebook Flux?
The state of your whole application is stored in an object tree within a single store
진실은 하나의 소스로부터📁
애플리케이션의 모든 상태는 하나의 스토어 안에 하나의 객체 트리 구조로 저장됩니다.
이미지 : Redux가 필요하다는 것을 언제 알 수 있나요?
데이터의 변경은 Reducer를 통해서 일어나며 그 데이터는 스토어에 저장된다. 리액트에서는 부모 컴포넌트가 자식 컴포넌트에서 데이터(상태)를 넘겨줄 수 있지만 이 데이터의 원천은 항상 스토어가 된다. 모든 변경 사항의 Store에 기록되기 때문에 데이터 흐름의 원천은 항상 'Store'이어야 한다.
상황과 필요에 따라 스토어를 여러개 만들 수도 있다. 하지만 너무 많은 스토어를 가진 Redux라면 MVC 패턴과 큰 차이가 있는지 생각해 봐야 한다.
서버로부터 가져온 상태는 시리얼라이즈되거나(serialized) 수화되어(hydrated) 전달되며 클라이언트에서 추가적인 코딩 없이도 사용할 수 있습니다. 또한 하나의 상태 트리만을 가지고 있기 때문에 디버깅에도 용이할 것입니다.
The only way to change the state is to emit an action, an object describing what happened.
상태는 읽기 전용이다 📑
상태를 변화시키는 유일한 방법은 무슨 일이 벌어지는 지를 묘사하는 액션 객체를 전달하는 방법뿐입니다.
View에서 일어나는 이벤트는 직접 데이터(상태)를 변경해서는 안 된다. 이벤트는 Action을 Reducer로 전달할 뿐이다. 데이터의 변경은 Reducer 만 할 수 있다. Reducer 이외의 공간에서는 데이터(상태)는 읽기모드인 것이다.
이를 통해서 뷰나 네트워크 콜백에서 결코 상태를 직접 바꾸지 못 한다는 것을 보장할 수 있습니다. 모든 상태 변화는 중앙에서 관리되며 모든 액션은 엄격한 순서에 의해 하나하나 실행되기 때문에, 신경써서 관리해야할 미묘한 경쟁 상태는 없습니다. 액션은 그저 평범한 객체입니다. 따라서 기록을 남길 수 있고, 시리얼라이즈할 수 있으며, 저장할 수 있고, 이후에 테스트나 디버깅을 위해서 재현하는 것도 가능합니다.
To specify how the state tree is transformed by actions, you write pure reducers.
변화는 순수 함수로 작성되어야한다
액션에 의해 상태 트리가 어떻게 변화하는 지를 지정하기 위해 프로그래머는 순수 리듀서를 작성해야합니다.
순수함수란?
이러한 순수 함수의 특징에 순수 Reducer는 2가지 특징을 더 갖는다.
리듀서는 그저 이전 상태와 액션을 받아 다음 상태를 반환하는 순수 함수입니다. 이전 상태를 변경하는 대신 새로운 상태 객체를 생성해서 반환해야한다는 사실을 기억해야 합니다. 처음에는 하나의 리듀서만으로 충분하지만, 애플리케이션이 성장해나가면 상태 트리의 특정한 부분들을 조작하는 더 작은 리듀서들로 나누는 것도 가능합니다. 리듀서는 그저 함수이기 때문에 호출되는 순서를 정하거나 추가적인 데이터를 넘길 수도 있습니다.
데이터가 집중화(Centralized) 되어 있어서 예측 가능하며(Predictable) 데이터 흐름이 단방향이라서 디버깅하기 쉽다(Debuggable). 또 리덕스와 연관된 좋은 생태계가 구축되어 있어서 필요에 맞게 유연하게(Flexible) 구현할 수 있다.
페이스북은 애플케이션 서비스가 커졌고 사용자와 인터렉션이 많아지면 MVC 패턴으로 유지하기 힘들어졌고 그래서 Flux와 Redux를 사용하게 되었다. 페이스북이 겪은 문제를 겪고 있다면 Redux를 사용하는 것이 좋지만 상태를 관리함에서 있어서 복잡성이 높지 않다면 반드시 리덕스를 써야 하는 것은 아니다. React 만으로도 충분히 단방향 데이터 흐름을 구현할 수 있다. 꼭 필요하지 않은 상태에서 Redux를 사용한다면 불필요한 라이브러리만 하나더 import 해서 애플케이션 번들 사이즈만 증가시킬 뿐이다.
이미지 : Redux가 필요하다는 것을 언제 알 수 있나요?
만약 React로 단방향 데이터 흐름을 구현할 경우 '과도한 prop drilling(prop 전달이 매우 많은 경우)'가 생기거나 디버깅이 어려움이 생긴다면 그때 Redux를 사용하자.
홍대 나오셨나요?