셍긱보다 별 거일 수도..
리덕스는 이제 프론트엔드 개발을 하는 사람이라면 한번쯤은 들어보거나 다뤄봤을 상태 관리 라이브러리입니다.
저는 항상 새로운 상태 관리 라이브리를 배울 때는 어떤 아이디어로 만들어졌고 무슨 모델을 기반으로 구현되었는지 살펴봅니다.
이 글을 읽는 여러분도 항상 tutorial 페이지로 넘어가기 전에 core concept에 대해 꼭 읽어보시는 것을 추천합니다.
라이브러리에 대한 코어 컨셉트와 주요 아이디어를 무시한다면, 나중에 엔지니어링 관점에서 문제를 해결할 때 왜 이 라이브러리를 사용해야 하는지 설명할 수 없게 됩니다.
단순 코더가 아니라 엔지니어가 되기 위해 우리는 이 점을 유의해야 합니다.
꼰?
javascript에는 Array.prototype.reduce 라는 네이티브 유틸 함수가 있습니다.
이 함수를 살펴보면 시그니처는 <T>((prev:T, current: T) => reduced: T, initialValue: T) => T
인데요,
여기서 첫 인자인 <T>(prev:T, current: T) => T
콜백 함수는 array를 돌면서 현재까지 누적된 T 값인 prev와 현재 array에서 조회중인 인덱스의 값 T 타입을 인자로 받고 새로운 누적값 T 타입을 반환합니다.
여기서의 콜백 함수를 리듀서라고 부르는데요,
이 리듀서는 이전 값과 현재 값만을 가지고 새로운 누적값을 만들어 냅니다.
const numbers = [2, 5, 8]
const addNumbers = (previousResult, currentItem) => {
console.log({ previousResult, currentItem })
return previousResult + currentItem
}
const initialValue = 0
const total = numbers.reduce(addNumbers, initialValue)
// {previousResult: 0, currentItem: 2}
// {previousResult: 2, currentItem: 5}
// {previousResult: 7, currentItem: 8}
console.log(total)
// 15
이는 리덕스 리듀서의 action 배열에 리듀서를 적용한 부분과 매우 유사한 모습을 띄는데요,
const actions = [
{ type: 'counter/increment' },
{ type: 'counter/increment' },
{ type: 'counter/increment' }
]
const initialState = { value: 0 }
const finalResult = actions.reduce(counterReducer, initialState)
console.log(finalResult)
// {value: 3}
이런 컨셉은 리덕스의 리듀서와 다음의 부분에서 일치합니다.
차이점은
이거.. 썸네일로 괜찮을 지도?
redux의 상태값을 변화시키는 유일한 방법은 store.dispatch를 사용하는 것입니다. 그리고 이렇게 상태를 변화시키는 방법을 제한했기 때문에 리덕스는 상태 변경을 미리 예측할 수 있는 장점을 가질 수 있게 되었습니다.
dispatch는 이벤트 버스 아키텍쳐의 triger event
역할을 맡습니다.
diaptch 함수의 인자로 action object를 넣어 호출하게 되면 event가 trigger되고 리듀서는 해당 action을 받아 새로운 상태 값을 반환합니다.
reducer는 이벤트 버스 아키텍쳐의 event listener
역할을 맡습니다.
MVC 아키텍쳐를 기반으로 만들어진 웹에서 상태 기반 업데이트를 하는 웹 어플리케이션이 주류로 자리잡으면서 컴포넌트 각 내부에서 상태를 가지는 형태가 자연스럽게 되었습니다.
근데 컴포넌트의 계층화가 세분화되고 각 컴포넌트가 하나의 거대한 트리 구조의 형태를 띄며 컴포넌트 간 상태를 업데이트 하고 조회하는 연결고리가 매우 복잡하게 얽히게 되었습니다.
음, 여기서 컴포넌트 간의 거리가 멀다고 하나의 UI 표현을 두 개의 각기 다른 메모리를 차지하고 있는 상태 객체가 맡는다면 MVC 패턴에서 발생했던 동일한 문제가 발생하게 됩니다.
게다가 react 같은 SPA를 사용할 때 lifting state up 기법을 써야 하는데, props도 많아지고 특정 컴포넌트가 다른 컴포넌트에 강하게 결합되면서 컴포넌트 재사용성이 떨어지게 되는 경우가 많이 발생합니다.
리덕스는 전역 상태 스토어를 제공함으로 앱에서 여러 컴포넌트가 조회하는 공통 상태 값의 single source of truth
를 만들어주게 되었고,
리듀서가 순수함수로 작성되었고, 상태를 업데이트하는 과정 자체가 단순 컴포넌트가 내부에서 자신만의 상태를 관리하는 아래의 그림 처럼 단순화 되었기 때문에 언제, 어떻게, 어디서 상태가 업데이트 되는지에 대해 예측하기 쉬워졌습니다.
컴포넌트
리덕스
리덕스가 Prop drilling을 줄여주기 위해서 나온 것은 올바른 설명이 아니라고 생각합니다.
애초에 prop을 사용하는 리엑트만을 위해 만들어진 라이브러리가 아닙니다.
그리고 리엑트는 해당 문제를 해결하기 위해 내부적으로 contextAPI를 제공함으로 이를 해결하고 있습니다.
덕분에 리덕스에 아주 약간의 흥미가 생겼어요!~