Mobx(2)
Mobx + React
react 가 종속된 프레임워크가 아니듯 Mobx도 하나에 종속된 라이브러리가 아니다. 그러기에 전에 Mobx(1)에는 javascript에 불러와 예제를 써보았다. 이번엔 리액트에 맞춰 보려고한다.
class Counter extends Component {
number = 0;
increase = () => {
this.number++;
}
decrease = () => {
this.number--;
}
render() {
return (
<div>
<h1>{this.number}</h1>
<button onClick={this.increase}>+1</button>
<button onClick={this.decrease}>-1</button>
</div>
);
}
}
decorate(Counter, {
number: observable,
increase: action,
decrease: action
})
export default observer(Counter);
예제1
다른점은 decorate 를 사용 했다는 점이다.... (decorator 사용하기위한 설정은 notice에 기록.)-->
this.setState를 통해서 변화된 state 값을 변형 시키고 입력했는데
Counter 클래스를 decorate로 감싸고 number를 지켜보는 상태에서(관찰 obserable)
증가, 감소 함수에 대해 action을 설정해주고 있다.
변화된 카운터들은 다른 부모?에서 반영이 된다.
(뭔가 많이 줄여진 기분이다.)
리액트에서 MobX를 사용할 땐 리덕스에서 했던 것 처럼 따로 다른 파일로 스토어를 만들 필요도 없고(필요하면 만들 수도 있습니다) 그냥 컴포넌트에 바로 적용해줄 수 있습니다. //REDUX 차이점
decorate(Counter, {
number: observable,
increase: action,
decrease: action
})
export default observer(Counter);
decorator(문법) 로 더 편하게 사용할수 있다고 한다..
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;
decorator
데코레이터(java 애노테이션과 유사하다고 보면 된다)를 제공하기 때문에 Redux를 사용할 때 React Component와 state를 연결 하기위한 mapStateToProps, Redux action을 연결을 위한 mapDispatchToProps 그리고 bindActionCreators…. 등등의 보일러플레이트 코드가 사라지고 데코레이터가 처리하기 때문에 깔끔한 코드가 생성됩니다.
스토어 분리
스토어?
:리덕스에서는 프로젝트에 적용하게 되면 이렇게 스토어 라는 녀석이 생깁니다. 스토어 안에는 프로젝트의 상태에 관한 데이터들이 담겨있죠.
즉 우리가 상태에 관한 액션이나 함수 등등 관리대상을 하나의 것으로 따로 분리 시킨것 같다.
그림 예제(리덕스)
MobX 에도 리덕스처럼 스토어라는 개념이 있다고 한다. 리덕스는 하나의 앱에는 단 하나의 스토어만 있지만, MobX 에서는 여러개를 만들어도 된다.
(inject를 사용하여 자바처럼 주입하면되지만, 리덕스에서는
reducerCombine으로 합쳐 단일 스토어로 사용해야한다.)
( 리액트와 다른점은 하나의 클래스에 observable 값이랑 함수들을 만들어주면 끝!)
Text
import { observable, action } from 'mobx';
export default class CounterStore {
@observable number = 0;
@action increase = () => {
this.number++;
}
@action decrease = () => {
this.number--;
}
}
점점 줄어들어서 불안하다...
MobX에서 프로젝트에 스토어를 적용 할 때는, Provider 라는 컴포넌트를 사용한다.
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'mobx-react'; // MobX 에서 사용하는 Provider
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import CounterStore from './stores/counter'; // 방금 만든 스토어 불러와줍니다.
const counter = new CounterStore(); // 스토어 인스턴스를 만들고
ReactDOM.render(
<Provider counter={counter}>
{/* Provider 에 props 로 넣어줍니다. */}
<App />
</Provider>,
document.getElementById('root')
);
registerServiceWorker();-------> notice 에 서비스 워커에 대한 설명이 있는 블로그 주소 기입
inject 함수는 mobx-react 에 있는 함수로서, 컴포넌트에서 스토어에 접근할 수 있게 해줍니다. 정확히는, 스토어에 있는 값을 컴포넌트의 props 로 "주입"을 해줍니다.
import React, { Component } from 'react';
import { observer, inject } from 'mobx-react';
@inject('counter')
@observer
class Counter extends Component {
render() {
const { counter } = this.props;
return (
<div>
<h1>{counter.number}</h1>
<button onClick={counter.increase}>+1</button>
<button onClick={counter.decrease}>-1</button>
</div>
);
}
}
export default Counter;
inject 함수는 mobx-react 에 있는 함수로서, 컴포넌트에서 스토어에 접근할 수 있게 해줍니다. 정확히는, 스토어에 있는 값을 컴포넌트의 props 로 "주입"을 해줍니다.
import React, { Component } from 'react';
import { observer, inject } from 'mobx-react';
@inject('counter')
@observer
class Counter extends Component {
render() {
const { counter } = this.props;
return (
<div>
<h1>{counter.number}</h1>
<button onClick={counter.increase}>+1</button>
<button onClick={counter.decrease}>-1</button>
</div>
);
}
}
export default Counter;
Mobx의 기본개념 및 특징
Mobx Store와 React 컴포넌트를 연결하는 방법은 Redux와 달리 @inject 데코레이더 한줄로 이루어 집니다
Mobx Store와 React 컴포넌트를 연결하는 방법은 Redux와 달리 @inject 데코레이더 한줄로 이루어 집니다
차트에서 기존의 객체가 영향을 받지않기위해서 assign메서드를 이용하였었다
(DEXI정렬, 차트 같은곳)
Redux에서는 다음과 같은 방법으로 처리를한다.
state 저장소의 불변성
// 초기 값을 지정해 놓은 state, 그냥 단순한 객체 리터럴이다 자신의 값을 처리하는 비즈니스 로직을 가진 메소드는 없다 (그냥 값만 있음)
const initialState = {
isLoading: false,
isOpent: false,
riderList: []
};
function riderReducer(state = initialState, action) {
switch (action.type) {
case types.FETCH_SUCCESS:
return {
...state,
riderList: action.payload.data
};
case types.FETCH_FAIL:
return {
...state,
isError: true
};
}
}
리듀서에서는 불변성 유지를 위해서 기존 state를 변경하는 것이 아닌 새 변경한 값으로 객체를 생성한 state를 리턴한다 변경하지 않는 값들은 스프레드로(...) 객체를 풀어서 넣어주고 변경할 값들은 변경해서 원래 state와 같은 모양으로 만든다
-->이를 편리하게 하기위해 Immutable.js라이브러리를 사용한다.
mobx에서는 동적으로 추가가 가능하다
object.assign를 사용하여도되지만 mobx가 제공하는 api가 존재한다.(extendObservable)
Component에서 컨트롤 역할을하고 store에서 서비스역할을하고 비동기로 받아오는 데이터를 repository역할처럼 보인다. store도 어노테이션을 통하여 쉽게 주입시켜 사용하고 스프링과 비슷한 느낌을 줍니다.
밑에 예제는 VO 게터 세터를 이요하는 형태와 비슷하다
@Autobind
class RiderModel {
/**
생성자에서 서버로 부터 받아온 JSON에 서 property와 value 추가 해버를 것 이므로 property를 미리 선안 안해도 관계는 없다.
id;
riderName;
status;
agencyName;
*/
constructor(data) {
extendObservable(this, data);
}
@computed
get riderWithAgency() {
return `${this.riderName}(${this.agencyName})`;
}
// 내부 처리시 상태값을 확인하는 메소드임으로
// ReactComponent에서 redering 할일이 없는 값이라면 구지 @computed를 붙일 필요는 없다
get isActive() {
this.status === "ACTIVE";
}
}
*****
reference저장할때 obj 와의 관계를 상실하기 때문에 내가 한방법은 render나 contructor안에서 바인딩 해줫는데 오토바인딩 데코레이터를 사용하는 방법도 있다.
Mobx(2)
By Beom lee
Mobx(2)
- 136