Redux의 탄생동기와 철학 이해하기
리덕스는 생각보다 간단한 라이브러리다. 데이터의 흐름이 단방향 으로만 흐른다는 것을 기억하고, 데이터의 흐름에 맞는 함수들만 작성해 주면 보다 더 쉽게 상태관리가 가능하다.
보통 리액트에서 리덕스를 많이 쓰기 때문에, 바로 리액트에 리덕스를 붙이게 되는데 그럼 리덕스의 단방향 데이터 흐름이란 철학을 이해하기 쉽지 않다. 이 철학이 이해되지 않은 상태에서 코드를 따라 치다보면 어느새 길을 잃고 방황하게 되어있다.
단방향 이라고 함은 데이터를 변화시키는데에 규칙이 있다는 뜻이다.
리덕스 라이브러리의 철학 === 규칙 이다. 이것을 잘 지켜야 아름답고 쉬운 상태관리를 할 수 있다.
아래는 공식 사이트에서 꼭 짚고 넘어가야 할 문장들을 해석 해 봤다.
리덕스 탄생동기
- SPA(Single Page Application) 들이 탄생하게 되어서 우리의 코드는 예전보다 더 많은 상태를 관리하게 되었다.
- 항상 변화하는 state를 관리하기란 쉽지 않다. 이벤트가 수없이도 많이 발생해서 데이터를 바꾸는 Single Page App 에서 언제, 왜, 어떻게 상태가 변화하는지를 감지하기란 힘든일이다.
- 복잡하게 느끼는 이유는 두가지 컨셉을 핸들링해야하기 때문이다. 사람의 머리로는 이해하기 쉽지 않은 두가지 컨셉: mutation(변화)와 asynchronicity(비동기). 멘토스와 코카콜라를 섞으면 폭발하듯, 우리의 머리도 상태의 변화와 비동기를 한 번에 이해하려고 들면 열이나서 곧장이라도 터질 준비를 한다. 따로따로 두가지 개념은 훌륭하다. 하지만, 함께하면 엉망진창이 된다. React와 같은 라이브러리는 이런 문제를 해결하기 위해서 view 단에서 비동기와 직접적인 DOM 접근을 막는다. 하지만 데이터의 상태를 관리하는 것은 개발자에게 맡겨져 있는데, 이 때 리덕스가 등장한다.
리덕스의 세가지 철학
1. Single Source of truth
전역 상태관리를 위해서 오직 한가지의 스토어(저장공간) 안에 object tree(객체트리)에 저장된다. 하나의 객체 트리는 어플리케이션을 디버깅 하거나 검사하는 것을 쉽게 만들어 준다. 예를들어, Undo/Redo 와 같은 전통적으로 어렵다고 여겨졌던 기능들도 이 원칙을 적용하면 구현하기에 꽤나 쉬운일이 된다.
2. State is read-only
내 생각에는 이 철학이 가장 중요한 것 같다. 스토어 안에 저장된 상태는 오직 읽기 전용이고, 무슨 일이 일어나는지를 정의하는 객체인 action에 의해서만 변경된다.
풀어서 이야기하면 리덕스의 스토어에 저장된 상태는 읽을수만 있고, 상태를 변경시키기 위해서는 액션을 발행해야 한다. 이것이 즉 데이터의 단방향 흐름이다.
데이터는 오직 액션을 통해서만 변경되고, 리덕스 스토어의 상태는 읽기 전용이다. 직접적인 데이터 변화는 허용하지 않는다.
이 원칙은 mutation(화면의 변화) 또는 asynchronicity(네트워크 콜백함수) 가 직접적으로 상태를 변화시키는 것을 막는다. 대신에, 상태를 변화시킬 것이라는 의도만을 표현하도록 한다. 모든 변화들이 하나의 스토어로 집중화 되어있고, 오직 한가지의 엄격한 순서(단방향)에 의해 일어나기 때문에, 알아차리기 어려운 미묘한 데이터 변화의 순서 경쟁이 없다. 또한 액션들이 간단한 객체이기 때문에, 기록되고, 직렬화되고, 저장되고 그리고 나중에 디버깅이나 테스트 목적으로 재사용될 수 있다.
순수한 Redux 코드를 보면 아래와 같다. 스토어에 액션을 발행시키는 행위다. 액션은 아래와 같이 그저 객체일 뿐이다. 그 객체는 type을 가지고 데이터를 변화시키기 위한 재료(payload)를 가진다.
action
3. Changes are made with pure functions
변화는 순수한 함수들로 만들어진다. 앞서서 액션객체 의해 변화를 한다고 했다. 그럼 어떻게 변화를 만들어 낼지에 대한 것이 Reducer 함수다.
Reducer 함수는 순수함수로써 이전의 상태와 액션을 인자로 받고, 변화된 상태를 리턴한다. 기억해야 할것은, 순수함수란 점이다. 쉽게 말해 오로지 결과만을 바꾸는 함수를 의미한다. 따라서, 이전의 상태를 변화시키는 것 대신에 새로운 state 를 생성 해 낸다.
Reducer
위의 코드에서도 볼 수 있다시피, Redux를 잘 활용하려면 새로운 배열을 내뱉는 map, reduce, filter 와 같은 함수들을 잘 사용해야 한다. 또한, reducer 함수로 들어온 상태 데이터의 불변 규칙을 지키기 위해서 배열과 객체를 맘대로 수정해서는 안된다. 여기서 또한 spread syntax가 자주 사용되는데, 결국은 JavaScript 에 능숙하면 할 수록 Redux 로 코딩하는 일이 즐거워 진다.
따라서, 리액트에 리덕스를 적용하는 것을 너무 서두르지 말자. 리덕스의 데이터를 변화시키는 철학과, 자바스크립트의 코드를 차근 차근 다시 살펴보는 시간을 갖고나면, 리덕스가 얼마나 좋은 철학으로 우리의 리액트 앱의 상태관리에 이바지 하는지를 깨닫게 된다.