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