Mobx

개요

Velopert 님의 말을 빌리자면 리액트에 흑마법을 끼얹은 느낌이라고 한다. 리액트가 불변성을 추구하면서 개발을 해야하는 반면, Mobx 에서 불변성은 크게 신경쓰지 않아도 된다. Mobx 를 처음 사용한다면 새로운 React 프로젝트를 하는 느낌이 들 정도로 개발의 방향성, 방법이 크게 달라질 것이다.
어플리케이션 상태에 따라서 자동으로 파생되어야할 것들이 자동으로 실행되는 것이 기본 개념입니다 (UI 뿐만이 아니라 서버 요청, 데이터 serialization 등)

Core Concepts

Observable State

변화를 통해서 reaction 을 할 value 들을 observable 로 선언할 수 있다. observable 한 값들이 변할 때 다양한 reaction을 정의할 수 있다. (UI 를 리랜더링 한다던가 등)
import { observable } from "mobx" class Todo { id = Math.random() @observable title = "" @observable finished = false }
JavaScript
복사

Computed value

computed value 는 관련 데이터(observable) 가 수정될 때마다 자동으로 파생되는 value.
class TodoList { @observable todos = [] @computed get todoCount() { return this.todos.length } @observable num = 1; @computed get double() { return this.num * 2; } } // todos 가 추가되거나 todos 내의 todo.finished 가 업데이트 될 때마다 unfinishedTodoCount // 값이 갱신된다.
JavaScript
복사

Reaction

Reaction 은 Computed 와 비슷하지만 새로운 값을 생성하는 것 대신 console 을 출력한다던가, network-request, react component re-render 등과 같은 side-effect 를발생시킨다.
마찬가지로 observable 한 값이 수정될 때마다 실행된다.
autorun(() => { console.log("Tasks left: " + todos.unfinishedTodoCount) })
JavaScript
복사
react 의 경우 mobx-react 의 observer 함수를 통해서 reactive 한 component 를 생성할 수 있다.
import { observer } from "mobx-react" @observer class TodoListView extends Component { render() { return ( <div> <ul> {this.props.todoList.todos.map((todo) => ( <TodoView todo={todo} key={todo.id} /> ))} </ul> Tasks left: {this.props.todoList.unfinishedTodoCount} </div> ) } } const TodoView = observer(({ todo }) => ( <li> <input type="checkbox" checked={todo.finished} onClick={() => (todo.finished = !todo.finished)} /> {todo.title} </li> ))
JavaScript
복사

Actions

redux 와는 다르게 Mobx 는 어떻게 events 를 컨트롤 해야하는지 정해진 규격이 없다.
event 를 firing 시키는데 어떠한 기술적인 필요가 없고, 단지 observable 한 값이 변하면 자동으로 react 한다.
store.todos.push(new Todo("Get Coffee"), new Todo("Write simpler code")) store.todos[0].finished = true
JavaScript
복사
명시적으로 action 함수로 정의하는 것도 가능하다.
class TodoListView extends Component { ... @action addTodo(name: string) { store.todos.push(new Todo("Get Coffee"), new Todo("Write simpler code")) store.todos[0].finished = true } }
JavaScript
복사
이 action 을 사용함에 있어서의 이점은 변화를 한꺼번에 일으켜서 변화가 일어날 때 마다 reaction 들이 나타나는것이 아니라, 모든 액션이 끝나고 난 다음에서야 reaction 이 나타나게끔 해줄 수 있다.

결론

개인적으로 근래 react 관련 제일 신선했던 라이브러리다. redux 만 알고 있던 내게는 신세계였다. 이유는 모르겠지만 redux 를 사용할 때보다 더 재미있게 사용해본 것 같다.
또 개인적인 의견이지만 redux 보다 상대적으로 러닝 커브가 낮다고 생각이 든다.
그리고 class 를 통해서 데이터를 구조화 할 수 있다는 점과 다양한 데코레이터로 편하게 사용 가능하다는 점이 매력적이었다. 객체지향에 익숙하면 좋아할 만한 구조다.
불변성을 유지하기 위한 노력이 불필요하다는 장점이 있다. 하지만 동시에 단점이 될 수 있지 않을까 하는 걱정도 있다. state 를 변경시키는 것 외에 다른 side-effect 를 자유롭게 발생시킬 수 있다는 점. 이 부분에 있어서 디버깅이 어려울 수도 있겠다는 생각이 든다.
다양하고 복잡한 data model 이 있는 프로젝트에서 편하게 사용할 수 있을 것 같다.
아직은 redux 를 사용하는 사람이 더 많지만... 언젠가는 따라잡을...까? 아무튼 현재로선 개발도구나 서드파티 라이브러리가 redux 가 더 많긴 하다.
최적화가 더 쉽게 되어있다.