MobX


MobX란?


Simple, scalable state management

https://github.com/mobxjs/mobx


mobx는 redux처럼 state를 관리해주지만, redux와는 다른점이 좀 있는 라이브러리입니다.

위에서 명시하여쓴 간단하고, 확장 가능한 상태 관리 도구입니다.


주요 특징


* 데코레이터(Decorator) 를 적극 활용합니다. -> Decorator에 대해서는 mobx 포스팅을 마친뒤 별도로 포스팅 하여 링크하겠습니다.                                                

* Typescript를 base로 만들어졌기 때문에 typescript에 대한 지원이 좋습니다.

* Redux와는 매우 큰 차이로, 단일 스토어를 강제하지 않습니다!

* 처음 사용이 Redux보다는 쉽습니다.



mobx의 전체적인 동작을 나타낸 그림인데요,

그림에 대한 설명은 예제를 통해 알아보면서 이해할수 있도록 해보겠습니다.


이제 CRA를 이용해 프로젝트를 생성하는것은 익숙해지셨을것입니다.

새로운 프로젝트를 생성해주세요.

그리고 App.tsx는 containers 폴더로 이동하고 index.tsx 파일 생성과,

component 폴더 생성 및 index.tsx 생성까지 해주세요.




매우 간단한 MobX 예제 따라하기


step 1 - state 객체를 정한다. -> 리액트의 state가 아니다.

step 2 - 정한 state 객체에 @observable 데코레이터를 붙인다.

step 3 - state 값을 다루는 함수들을 만든다.

step 4 - state 값이 변경되면 반응하는 컴포넌트를 만든다. -> 이 컴포넌트에 @observer 붙인다

step 5 - 컴포넌트에서 state값을 사용한다.

step 6 - 컴포넌트에서 state값을 변경하는 함수를 사용한다.



Step 1 ~ 2


src폴더에 stores 폴더를 생성해주세요. 그리고 index.tsx 파일과 AgeStore.tsx 파일을 생성해주세요.


src/stores/AgeStore.tsx

import { observable } from 'mobx';

export class AgeStore {
@observable
age: number = 30;

}


우선 기본적으로 클래스를 만들고 그 안에 age 라는 값을 명시합니다.

여기서 감지할 값에 @observable 을 사용해줘야 하는데, 여기서는 age 값에 해주겠습니다.

observable은 mobx 에 있는 기능이므로, mobx를 설치해주세요.


yarn add mobx

혹은 

npm install --save mobx 


자 그런데, 이렇게 해도 아마 에디터에서는 오류를 내며 뭐라뭐라 할것입니다.

왜냐하면 @ observable은 데코레이터인데, typescript에서 데코레이터를 사용하기 위해서는

tsconfig의 설정에서 experimentalDecorators 값을 true로 해주어야 합니다.

하지만 디폴트값이 false로 되있기 때문에 직접 true로 바꿔 줘야 합니다.


tsconfig.json

{
"compilerOptions": {
"outDir": "build/dist",
"module": "commonjs",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"experimentalDecorators": true // 데코레이터를 사용하기 위해 true로 변경
},
"exclude": [
"node_modules",
"build",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts"
],
"types": [
"typePatches"
]
}


src/stores/index.tsx

import AgeStore from './AgeStore';

export { AgeStore };


Step 3


이제 함수를 생성해 주겠습니다.

기본적으로 state 값을 가져오는 get 함수와 set 함수를 생성하도록 하겠습니다.


import { observable } from 'mobx';

export default class AgeStore {
@observable
private _age: number = 30;

constructor(age: number) {
this._age = age;
}
public getAge(): number {
return this._age;
}
public setAge(age: number): void {
this._age = age;
}

}


Step 4


Age component를 만들겠습니다.


src/components/Age.tsx

import * as React from 'react';

class Age extends React.Component<{}, {}> {
constructor(props: {}) {
super(props);
}
render() {
return (
<div className="Age">
</div>
);
}
}

export default Age;


src/components/index.tsx

import Age from './Age';

export { Age };



Step 5 ~ 6


컴포넌트에서 age값을 사용해보도록 하겠습니다.


import 해주시고

import { AgeStore } from '../stores';


생성해줍니다. ( store라고 생각하시면 됩니다. )

const ageState = new AgeStore(30);


render() {
return (
<div className="Age">
<h1>{ageState.getAge()}</h1>
<button onClick={() => this.addAge()}>한해가 지났다.</button>
</div>
);
}


그리고 값이 증가하는 함수와 버튼까지 추가해 보도록 하겠습니다.


import * as React from 'react';

import { AgeStore } from '../stores';

const ageState = new AgeStore(30);

class Age extends React.Component<{}, {}> {
constructor(props: {}) {
super(props);
this.addAge = this.addAge.bind(this);
}
render() {
return (
<div className="Age">
<h1>{ageState.getAge()}</h1>
<button onClick={() => this.addAge()}>나이증가</button>
</div>
);
}
addAge() {
const age = ageState.getAge();
ageState.setAge(age + 1);
console.log(ageState.getAge());
}
}

export default Age;


이제 실행해보겠습니다.



버튼을 아무리 눌러도 값이 변하는것처럼 보이지는 않습니다.


그런데 제가 위의 코드에 addAge 함수에 console.log를 하나 삽입해 놓은것이 있습니다.


개발자 도구로 로그를 살펴보겠습니다.



값은 증가하는데, 렌더링 적용만 안되었다고 추론할수 있습니다.


이제 @observer 를 적용시켜 보겠습니다.


observer 는 mobx-react 를 설치해야 사용 가능합니다.


yarn add mobx-react

혹은

npm install --save mobx-react


import * as React from 'react';

import { AgeStore } from '../stores';

import { observer } from 'mobx-react';

const ageState = new AgeStore(30);

@observer
class Age extends React.Component<{}, {}> {
constructor(props: {}) {
super(props);
this.addAge = this.addAge.bind(this);
}
render() {
return (
<div className="Age">
<h1>{ageState.getAge()}</h1>
<button onClick={() => this.addAge()}>나이증가</button>
</div>
);
}
addAge() {
const age = ageState.getAge();
ageState.setAge(age + 1);
console.log(ageState.getAge());
}
}

export default Age;


간단하게 observer를 import하고, 사용할 컴포넌트 위에 @observer 를 명시해줍니다.


실행해주세요.



이제 정상적으로 렌더링이 됩니다.


즉, 변화를 감지하고 싶은 대상에는 observable 데코레이터 를 사용하고,

observable된 값 변화에 따라 반응하는 컴포넌트에는 observer 데코레이터를 사용하여

제어하는 간단한 구조입니다.


뭔가 redux보다는 확실히 중간 과정이 편한 느낌입니다.

redux는 액션타입을 지정하고, 액션 크리에이터 함수를 만들고, 리덕스를 만들고, 스토어 생성한다음,..... 많은 과정이 필요하지만, mobx는 그 과정이 정말 최소화된 느낌입니다.


물론 각각의 장단점이 있으리라 생각되지만, 더 공부를 해야 확실하게 생각을 말할수 있을거 같습니다.


이번 포스팅은 간단하게 끝내고, 다음 포스팅도 계속해서 mobx에 대해 포스팅을 하도록 하겠습니다.


감사합니다.



소스코드 주소입니다.


https://github.com/JaroInside/tistory-react-typescript-study/tree/14.mobx-part1



참고 슬라이드 - http://slides.com/woongjae/react-with-typescript-4#/

참고 동영상 - https://www.youtube.com/playlist?list=PLV6pYUAZ-ZoHx0OjUduzaFSZ4_cUqXLm0

'React > React&typeScript' 카테고리의 다른 글

14.mobx-part3  (0) 2017.08.03
14.mobx-part2  (0) 2017.08.01
13. redux - part5  (0) 2017.07.26
13. redux - part4  (0) 2017.07.26
13. redux - part3  (0) 2017.07.25
블로그 이미지

Jaro

대한민국 , 인천 , 남자 , 기혼 , 개발자 jaro0116@gmail.com , https://github.com/JaroInside https://www.linkedin.com/in/seong-eon-park-16a97b113/

,