Redux란?
Redux는 어플리케이션의 클라이언트쪽 state를 관리하기 위한 거대한 이벤트루프이다.
리덕스를 사용하면 상태값을 컴포넌트에 종속시키지 않고, 상태 관리를 컴포넌트의 바깥에서 관리할 수 있게 된다.
액션 : 이벤트(상태에 변화를 일으킬 때, 참조할 수 있는 객체), 리듀서 : 이벤트에 대한 반응
Redux의 동기
리덕스는 클라이언트 앱의 복잡성을 제어하기 위한 하나의 state 제어 수단이라고 한다.
Redux는 Mutation, 클라이언트의 종합적인 State를 관리하기 위한 방법론이라면,
Redux의 Middleware를 장착하는 것으로 복잡한 비동기적인 API 처리, Action을 처리할 수 있다.
Redux의 원리
어플리케이션 전체에는 store라는 커다란 하나의 state 가 존재하는데 이것이 어플리케이션의 state를 총괄한다. store의 state는 그 자체를 직접 변형할 수는 없고, 오직 순수함수인 리듀서로만 새로운 형태로 갈아치우는 것이 가능하다. 리듀서는 type과 payloads를 속성으로 갖는 단순 객체인 단순 객체인 action 이벤트가 발생했을 때에만 작동하며, 이 action 이벤트를 발생시키는 방법은 dispatch라는 함수에 action을 넣는 것으로 가능하다.
순서
dispatch(action) 👉 리듀서 작동 👉 store의 state 변경 👉 변경된 state가 state를 subscribe하고 있는 컴포넌트에 전달
어플리케이션 전체 상태를 Redux로 관리하면?
-
application state의 변화가 예측가능하게 변한다. 특정 Action이벤트 발생에만 reducer가 작동하게 되기 때문에, store의 state가 변한 경우, 어떤 액션 이벤트로 인해 변경된 것인지 알 수 있다. 또한 정확히 어떤 액션 이벤트로부터 변경된 것인지 알 수 있어 Time travel debugging이 가능해진다. 즉, 뒤로가기 버튼이 있는 것처럼 되추적이 가능해진다는 것이다.
-
리듀서는 순수 함수(외부에 영향을 끼치지 않는 함수, api calling이 없는 함수)이기 때문에 test코드를 짤 수 있다. -> ?
-
선언적으로 프로그래밍을 할 수 있다.(Declarative Programming) 이게 무슨 소리지? 그래서 알아봤다. 어떤 방법으로 해야하는지(How)를 나타내기보다, 무엇(What)과 같은지를 설명하는 방식으로, 순수 함수를 조합하고 소프트웨어를 만드는 방식이다. 이건 또 무슨소리지? 그래서 알아봤다.
- 명령형 프로그래밍 👉 알고리즘을 명시하고 목표는 명시안함.
- 선언형 프로그래밍 👉 알고리즘 명시하지 않고 목표만 명시. What만 명시함.
Redux와 Middleware
action 이 단순 객체이기 때문에 다른 action 이벤트나 조건분기를 생성할 수 없기 때문에, action creator 를 이용하여 action을 생성하는 함수를 생성할 수 있다. action creator 는 함수이기 때문에, Promise나 Callback을 적절히 조화하는 것으로 다른 action 이벤트를 생성할 수 있고, 조건 분기도 가능해진다.
- 굳이 action을 반환할 필요도 없다. 원래 action create 를 하려면 dispatch 를 일일이 불러와야 하는데 우리는 Middleware로 redux thunk 를 사용하면서 이를 방지할 수 있다. redux thunk 는 함수를 반환하는 함수인데, dispatch를 가지고 함수를 wrapping하고 있어 dispatch를 일일히 불러오지 않아도 된다.
최종적으로 정리해보면, redux는 액션 이벤트를 발생시켜서 리듀서라는 이벤트에 대한 반응을 일으킴으로 어플리케이션의 state를 a -> b로 만든다.
Redux의 세 가지 규칙
-
하나의 어플리케이션 안에는 하나의 스토어가 있다. 하나의 어플리케이션 안에는 하나의 스토어를 만들어서 사용한다. 여러개의 스토어를 만들고 싶다면(특정 업데이트가 빈번하게 일어나거나 특정 파트를 분리 시킬 때), 가능은 하지만 그렇게 되면 개발 도구를 활용하지 못하게 된다.
-
상태는 읽기 전용이다. React에서 상태를 업데이트할 때, setState를 사용하고, 배열을 업데이트할 때는 배열 자체에 push를 직접하지 않고 concat같은 함수를 사용하여 새로운 배열을 만들어 교체하는 방식으로 업데이트를 한다. 깊은 구조로 되어있는 객체를 업데이트 할 때도 Object.assign을 사용하거나 spread를 사용하여 업데이트한다. 👉 리덕스에서도 마찬가지로, 기존의 상태를 건들이지 않고 새로운 상태를 생성하여 업데이트 해주는 방식으로 하면, 개발자 도구를 통해서 뒤로 돌릴 수도 있고 앞으로 돌릴 수도 있다. 리덕스에서 불변성을 유지해야 하는 이유는 내부적으로 데이터가 변경되는 것을 감지하기 위하여, shallow equality 검사를 하기 때문이다. 이를 통해 객체의 변화를 감지할 때, 객체의 깊은 곳을 검토하는 것이 아니라 겉핥기 식으로 비교를 하여 좋은 성능을 유지할 수 있는 것이다.
-
Reducer는 순수한 함수여야 한다.
- 리듀서 함수는 이전 상태와 액션 객체를 파라미터로 받는다.
- 이전 상태는 절대 건들이지 않고, 새로운 객체를 생성하여 반환한다.
- 똑같은 파라미터로 호출된 리듀서 함수는 언제나 같은 결과값을 반환해야 한다. // new Date나 랜덤숫자 생성의 경우엔, 순수하지 않은 작업이겠죠? (순수하지 않은 작업의 경우엔, Redux Middleware를 이용하여 작업합니다)
참고자료
리덕스란 무엇인가? : [Hueman] https://voidsatisfaction.github.io/2017/02/24/what-is-redux/