MST(mobx-state-tree)

왜 사용할까? (장점)

Immutable 한 객체 컨트롤이 가능하다
기존의 Mobx 만 사용하면 mutable 한 객체를 다루게 된다
@observable todos = []; todos[0].completed = false;
JavaScript
복사
하지만 MST 에서는 create 하면 자동으로 snapshot 이 생성된다.(MST에서이 자동으로 생성 된 불변 트리를 스냅 샷 이라 한다.) 참조하는 인스턴스의 속성을 수정하면 자동으로 새로운 불변 트리(스냅샷)이 생성된다.
state-tree 를 사용해서 구조화된 data type 을 이용하는 것이 가능하다
model 을 통해서 선언 후 사용한다.

types

타입을 미리 선언할 수 있다. runtime 에서 잘못된 type 을 선언할 시 error 를 throw 함

create instance

Model.create()
JavaScript
복사
위와 같이 create 함수를 통해서 생성한다. create 안에 model 에 대한 프로퍼티를 직접 전달할 수도 있다. model 에서 property 에 대해서 default 값이 정해져 있다면 그렇게 설정이 되겠지.
랜더링 되는 모든 render 에 대해서 쪼개서 observer 를 붙이면 render performance 를 향상시킬 수 있음
// 이 경우, todo 의 내용이 하나만 변경되어도 모든 todo 내용이 담긴 component 가 update 될 것 const App = observer(props => ( <div> <button onClick={e => props.store.addTodo(randomId(), "New Task")}>Add Task</button> {values(props.store.todos).map(todo => ( <div> <input type="checkbox" checked={todo.done} onChange={e => todo.toggle()} /> <input type="text" value={todo.name} onChange={e => todo.setName(e.target.value)} /> </div> ))} </div> ))
JavaScript
복사
// 다음과 같이 수정하면 수정된 todo 만 re-render 될 것이다. const TodoView = observer(props => ( <div> <input type="checkbox" checked={props.todo.done} onChange={e => props.todo.toggle()} /> <input type="text" value={props.todo.name} onChange={e => props.todo.setName(e.target.value)} /> </div> )) const AppView = observer(props => ( <div> <button onClick={e => props.store.addTodo(randomId(), "New Task")}>Add Task</button> {values(props.store.todos).map(todo => ( <TodoView todo={todo} /> ))} </div> ))
JavaScript
복사

computed properties

.views 함수 안에서 선언하면 된다.
const RootStore = types .model({ users: types.map(User), todos: types.map(Todo), }) .views(self => ({ get pendingCount() { return values(self.todos).filter(todo => !todo.done).length }, get completedCount() { return values(self.todos).filter(todo => todo.done).length } getTodosWhereDoneIs(done) { return values(self.todos).filter(todo => todo.done === done) } }))
JavaScript
복사
computed 된 property 는 observe 하고 있는 property 가 변경될 때마다 자동으로 다시 연산된다.

Reference

TODO model 에 User instance 를 할당할 수 있다.
const User = types.model({ id: types.identifier, name: types.optional(types.string, "") })
JavaScript
복사
위와 같이 identifier 를 선언함으로써, 재사용이 가능하도록 도와준다. identifier 는 수정 불가하며, 유일 값만 인정이 된다.

define reference

const Todo = types .model({ name: types.optional(types.string, ""), done: types.optional(types.boolean, false), user: types.maybe(types.reference(User)) }) // 만약 User instance 가 생성되기 전에 Todo 가 먼저 생성된다면 아래와 같이 선언할 수 있다. const Todo = types .model({ name: types.optional(types.string, ""), done: types.optional(types.boolean, false), user: types.maybe(types.reference(types.late(() => User))) }) .actions(self => ({ setName(newName) { self.name = newName }, toggle() { self.done = !self.done } setUser(userId) { if (userId === "") { // When selected value is empty, set as undefined self.user = undefined } else { self.user = userId } }, }))
JavaScript
복사

ETC

Snapshots are automatically converted to models when needed. So, the two following statements are equivalent: store.todos.push(Todo.create({ title: "test" })) and store.todos.push({ title: "test" }).