-
Concepts
MobX내에서 크게 3가지로 분류할 수 있다.
1. State
2. Actions
3. Derivations
1. State를 정의하고 state를 observable하게 한다.
State는 어플리케이션에서 drive(추출)한 data이다. state를 observable하게 함으로 MobX가 확인할 수 있다.
예시:
import { makeObservable, observable, action } from "mobx" class Todo { id = Math.random() title = "" finished = false constructor(title) { makeObservable(this, { title: observable, finished: observable, toggle: action }) this.title = title } toggle() { this.finished = !this.finished } }
위 예제는 makeAutoObservable을 사용해서 간소화 할 수 있다.
2. action을 통해 state 업데이트
state를 바꾸는 어떤 코드든 action이라 할 수 있다. 예를 들어 유저 이벤트, 백엔드 데이터 푸시, 스케줄 이벤트를 action이라고 할 수 있다.
위 예제에서 finished 값을 바꾸는 toggle이라는 메서드가 있고. finished가 observable하다.
observable한 값을 바꾸는 코드는 action이라 기록하는 것이 권장된다. 그럼 Mobx 알 수 있어 performance가 개선 될 수 있다.
3. state가 바뀌면 자동적으로 응답하는 derivation 생성하기
Derivation이란 state로 부터 부가적인 상호작용 없이 파생될 수 있는 그 어떠한 것을 의미한다. Derivation은 여러 형태로 존재한다:
- UI (user interface)
- Derived data, 예를 들어 todos에서 남은 수
- 백엔드 integrations, 변화된 것을 서버에 전송
MobX는 derivation을 두가지로 분류한다.
- Computed values, 현재 observable state로 부터 pure function을 통해 파생될 수 있는 것
- Reactions, state가 바뀌면 자동적으로 발생해야 하는 side effect.
MobX에 입문할 때 reaction을 남용하는 경향이 있다. current state를 기반으로 하는 value를 만들고 싶으면 computed를 사용하라.
3.1. Model derived values using computed
computed value를 만들고 싶으면, JS getter function의 get을 이용하고 makeObservable에 computed로 마크하라.
예시:
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 }) this.todos = todos } }
todo가 추가되거나 finished 속성이 변경되면 MobX가 unfinishedTodoCount가 update되도록 해준다.
3.2. Model side effects using reactions
reaction은 computed value와 비슷하지만 새로운 정보를 생성하기보단 console에 print, 네트워크 요청, DOM에 변화와 같은 side effect들을 야기한다.
3.3. Reactive React components
React를 사용하고 있다면 component를 observer로 감싸면 reactive하게 할 수 있다.
예시:
import * as React from "react" import { render } from "react-dom" import { observer } from "mobx-react-lite" const TodoListView = observer(({ todoList }) => ( <div> <ul> {todoList.todos.map(todo => ( <TodoView todo={todo} key={todo.id} /> ))} </ul> Tasks left: {todoList.unfinishedTodoCount} </div> )) const TodoView = observer(({ todo }) => ( <li> <input type="checkbox" checked={todo.finished} onClick={() => todo.toggle()} /> {todo.title} </li> )) const store = new TodoList([new Todo("Get Coffee"), new Todo("Write simpler code")]) render(<TodoListView todoList={store} />, document.getElementById("root"))
observer는 React component에서 render하는 data를 derivation로 바꾼다. MobX는 간단히 말하자면 component가 re-rendering 되야 할 때 re-rendering되도록 보장한다.
위 예제에서 onClick handler가 toggle action을 사용했으니 TodoView component가 re-rendering되게 한다. 하지만 unfinished task의 수가 변하면 TodoListView component만 re-render된다.
3.4. Custom reactions
사용하는 경우가 흔치는 않지만 autorun, reaction, when을 사용하면 특별한 상황에 맞는 reaction을 사용할 수 있다.
예시: autorun을 통해 unfinishedTodoCount의 값이 바뀔 때마다 log msg를 찍을 수 있다.
// A function that automatically observes the state. autorun(() => { console.log("Tasks left: " + todos.unfinishedTodoCount) })
실행 중인 tracking 되는 함수의 모든 observable property에 MobX가 반응하기 때문에 위와 같이 예시에서 unfinishedTodoCount가 바뀔 때마다 log msg를 print할 수 있다.
Principles 원칙
MobX는 단방향 data flow를 가진다.
즉, action은 state를 바꾸고, 이어서 영향 받는 view를 update하는 flow 형태를 띈다.
- 모든 derivation은 state가 바뀌면 자동적으로 atomically update된다. 따라서 intermediate value는 observe할 수 없다.
- 모든 derivation은 (default)기본적으로 동기적으로 update된다. 즉, action은 state가 바뀐 다음 computed value를 inspect해도 안전한다는 것을 의미한다.
- Computed value는 lazily update된다. actively 사용되고 있지 않은 computed value는 update되지 않고 side effect(I/O)때문에 필요할 때 비로소 update된다. view가 더 이상 사용되고 있지 않으면 자동적으로 garbage collect된다.
- 모든 computed value는 pure해야 한다. state를 바꾸어선 안된다.
'MobX' 카테고리의 다른 글
Render lists in dedicated components 리스트만을 위한 컴포넌트 (0) 2022.03.02 observable state 만들기 (0) 2021.05.26