npm install mobx mobx-react
const state = observable({
test1: 0,
test2: 1,
test3: 2,
})
autorun : 어떤 값이 변경되었을때 인식하게 되는것
autorun(() => {
console.log("change");
}
)
runInaction: 어떤값을 변경할것이라는것을 명시해주는것
runInaction(() => {
state.test1 = 1;
state.test2 = 2;
state.test3 = 3;
})
이렇게 햇을때에 autorun에는 change가 한번밖에 찍히지 않는데,
runInaction을 쭉 나열했을경우에는 한번만 인식하게된다.
import React, { Component } from 'react';
import { observable, action } from 'mobx';
import { observer } from 'mobx-react';
// **** 최하단에 잇던 observer 가 이렇게 위로 올라옵니다.
@observer
class Counter extends Component {
@observable number = 0;
@action
increase = () => {
this.number++;
}
@action
decrease = () => {
this.number--;
}
render() {
return (
<div>
<h1>{this.number}</h1>
<button onClick={this.increase}>+1</button>
<button onClick={this.decrease}>-1</button>
</div>
);
}
}
// **** decorate 는 더 이상 필요 없어집니다.
// decorate(Counter, {
// number: observable,
// increase: action,
// decrease: action
// })
// export default observer(Counter);
// **** observer 는 코드의 상단으로 올라갑니다.
export default Counter;
// **** 함수형태로 파라미터를 전달해주면 특정 값만 받아올 수 있음.
@inject(stores => ({
number: stores.counter.number,
increase: stores.counter.increase,
decrease: stores.counter.decrease,
}))
observable 변수가 수정 되면, MobX에 이벤트가 등록 된다 그렇게 차곡차곡 Stack에 쌓이고 하나하나 실행하며, 컴포넌트들을 Render 하는 방식이다. 놀랍게도 한 번의 이벤트 발생에 observable 변수 10개가 변화하면 10번의 랜더 이벤트가 call Stack에 추가 될 것이다.
이전에 페이지 한 번 로딩에 최상단 컴포넌트 render()가 50번 호출 된 적이 있었는데. MobX를 모르고 사용한 탓이다.
물론, DOM의 변경 사항이 없다면 VirtualDOM이 이를 지켜주지만 혹 Render()안에서 연산이 들어간다면 이 연산들은 실행 될 것 이고, 어찌 되었든 상태관리가 없는 것 보다는 심각한 기능 문제를 발생 시킬 수 있다.
MobX observable 변수가 변경 하면 이벤트 실행 목록에 하나씩 쌓이고, Render를 기다리게된다.
@observable private a = 0;
@observable private b = 0;
@observable private c = 0;
@observable private d = 0;
@observable private e = 0;
@observable private f = 0;
// @action
set() {
this.a = 1;
this.b = 2;
this.c = 3;
this.d = 4;
this.e = 5;
this.f = 6;
}
위 예제에서 6개의 이벤트가 생성 된다.
하지만, @action을 사용하면, 이를 하나의 이벤트로 만들 수 있다.
바인딩이 필요한 경우에는 @action.bound를 사용
@observable private browserWidth = 0;
constructor(props: HomePageProps) {
super(props);
window.addEventListener("resize", this.setBrowserWidth);
}
@action
setBrowserWidth() {
this.browserWidth = window.innerWidth;
}
결과 : 바인딩 되지 않아, 값 변하지 않음.
@action.bound
setBrowserWidth() {
this.browserWidth = window.innerWidth;
}
결과 : 정상적으로 바인딩이 되고, @action 처리도 진행
@computed get BrowserWidth() {
return this.browserWidth;
}
@computed는무조건 get 함수로 선언해야한다.
* 상위 Component에서 아래와 같이 store 값을 내려준다.
<Provider Store={Store}>
</Provider>
@inject(stores => ({
setStore : stores.Store.setStore,
groupLength : stores.Store.groupLength,
}))
@observer
class Test extends React.Component {
//...
const {setStore, groupLength} = this.props;
와 같이 사용 가능.