이 포스트는 다음 글을 참고하여 작성하였음을 알립니다.
React 또는 React Native에서 SPA 상태 관리 라이브러리로는 Redux가 전부이다.
현 회사의 App 프로젝트가 MobX로 되어 있기 때문에 이 참에 배워서 익힐 겸 포스트도 함께 작성한다.
위에서 언급했듯이 상태 관리 라이브러리 중 하나이다.
RTK 가 나오기 이전의 Redux 는 러닝 커브가 높아 사용하기에 부담스러웠다.
Action, Reducer, Dispatch, Store 등 숙지해야 할 개념도 많고 막상 사용하기도 쉽지 않았다.
이를 전부 간소화하고 가독성과 직관성을 높여 등장한 상태 관리 라이브러리가 바로 MobX 이다.
MobX 는 어플리케이션에서 다음 세 가지 개념을 구분한다.
state 는 Redux 에서도 언급했듯이, 어플리케이션을 구동하는 데이터 이다.
객체(Object), 배열(Array), 클래스 등 원하는 데이터 구조에 state를 저장한다.
변경하려는 state를 MobX 가 추적할 수 있도록 observable
로 표시한다.
observable
이란, 정의한 상태의 변경 등을 관찰하기 위해 필요한 메소드 정도로 보면 된다.
다음 예제를 보자.
import { makeObservable, observable, action } from "mobx"
class Todo {
id = Math.random()
title = ""
finished = false
constructor(title) {
makeObservable(this, {
title: observable, // here
finished: observable, // here
toggle: action
})
this.title = title
}
toggle() {
this.finished = !this.finished
}
}
초기값에서 선언한 것을 보면 알 수 있듯이 title, finished 이 두 가지 state를 observable
로 표시하여 앞으로 이 state들을 추적하겠다고 선언한 것과 다름없다.
action
이란, state를 변경하는 코드 조각이다.
Redux 에서 action은 state를 바꾸기 위해 필요한 명세서와 같은 역할을 했고 실제로는 reducer가 state를 변경했다.
하지만, MobX 에선 action 자체가 state를 변경한다.
toggle: action
앞선 예제를 보면 toggle 에 action
이 표시된 것을 볼 수 있다.
이는 앞으로 toggle 이라는 메소드로 observable
표시 된 상태를 변경하겠다라는 의미와 동일하다.
derivation
은 다음 두 종류로 구분한다.
computed 란, 현재의 observable
한 state
에서 순수 함수를 사용하여 파생될 수 있는 값을 뜻한다.
아래 코드를 보며 다시 설명하자면,
unfinishedTodoCount 는 makeObservable
메소드 안에 computed
로 표시되어 있다.
예를 들어 todo 배열에 값이 추가되거나 finished 속성 중 하나가 수정된다면, unfinishedTodoCount 역시 자동으로 업데이트 한다는 뜻이다.
import { makeObservable, observable, computed } from "mobx"
class TodoList {
todos = []
get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length
}
constructor(todos) {
makeObservable(this, {
todos: observable,
unfinishedTodoCount: computed // here
})
this.todos = todos
}
}
reaction 이란, state
또는 computed
값이 변했을 때, 최신 상태의 값을 화면에 그리는 작업을 뜻한다.
네트워크 요청, DOM 패치 등 상태가 변함에 따라 부수적인 것들을 적용하기 위해 최상단의 React 컴포넌트부터 트리를 타고 쭉 점진적으로 업데이트를 하며 부수효과를 생성한다.
즉, 간단히 말해 반응형 프로그래밍과 명령형 프로그래밍 사이를 연결한다.
observer
함수로 컴포넌트를 감싼 후 반응형으로 만든다.
이 포스트에선 mobx-react-lite
패키지를 사용한다.
🔔 참고
mobx-react-lite
란,
MobX를 React에 바인딩 해주는 패키지 종류 중 하나이다.
전통적으로 MobX는 클래스 기반 컴포넌트를 지원했으며 패키지 이름 역시mobx-react
였다.
이 패키지를 라이트 버전으로 만들어 함수형 컴포넌트만 지원하도록 만든 패키지가 바로mobx-react-lite
이다.
보통 observer
를 사용하여 함수형 컴포넌트를 만드는 문법은 대체로 아래와 같다.
export const RankingNewsCard = observer(function RankingNewsCard({ news }: { news: News }) {
return (
...
<Text style={[styles.titleText, { color: theme.colors.black700 }]} numberOfLines={2}>
{news.title}
</Text>
{news.img ? (
<Image style={styles.imgStyle} source={{ uri: news.img }} resizeMode="cover" />
) : (
<Image
style={[
styles.noneImgStyle,
{
borderColor: theme.colors.neutral100,
},
]}
source={require("assets/images/box.png")}
/>
)}
...
)
})
하기 이미지와 같이 MobX 는 Redux 와 마찬가지로 단방향 데이터 흐름을 사용하여 영향을 받는 모든 view 를 업데이트 한다.
구체적인 flow는 다음과 같다.
state
가 변경되면 모든 derivation
이 자동으로 원자 단위로 업데이트 된다.derivation
은 동기적으로 업데이트 된다.computed
값은 느리게 업데이트 된다.computed
값은 순수해야 하며 state
를 바꿔선 안된다.