- Published on
React에서 MobX 사용하기
MobX를 React와 사용하면 쉽게 State를 관리할 수 있고, setState도 사용하지 않아도 된다.
MobX 설치 및 decorator 설정
-
npm install mobx mobx-react
-
npm @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators
-
decorator를 사용하기 위해 .babelrc를 수정해준다.
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"regenerator": true
}
],
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose": true }]
]
}
MobX Store 구현
src/stores/index.js
- RootStore를 만들어서 import한 스토어들을 생성할 때 this로 RootStore를 전달해주면 RootStore를 통해서 다른 Store에 접근할 수 있다.
import CounterStore from './counter';
import MarketStore from './market';
class RootStore {
constructor() {
this.counter = new CounterStore(this);
this.market = new MarketStore(this);
}
}
export default RootStore;
src/stores/counter.js
- this.root.market.list 와 같이 market store의 list에 접근할 수 있다.
import { observable, action } from 'mobx';
export default class CounterStore {
@observable number = 0;
constructor(root) {
this.root = root;
}
@action increase = () => {
this.number += 1;
};
@action decrease = () => {
this.number -= 1;
};
}
src/index.js
- React 프로젝트에 MobX 스토어를 적용할 때는 Provider 컴포넌트를 사용한다.
- root store에 있는 counter, market 스토어를 Provider에 전달한다.
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'mobx-react';
import './index.less';
import App from './App';
import RootStore from './stores';
const root = new RootStore();
ReactDOM.render(
<Provider {...root}>
<App />
</Provider>,
document.getElementById('root')
);
React 컴포넌트에 Store 주입
-
mobx-react의 inject를 통해 컴포넌트에서 store에 접근할 수 있다. store에 있는 값을 컴포넌트의 props 로 주입해준다.
-
setState를 사용하지 않아도 mobx-react의 observer가 observable 값이 변할 때 컴포넌트의 forceUpdate를 호출하게 함으로써 변화가 화면에 반영된다.
import React, { Component } from 'react';
import { observer, inject } from 'mobx-react';
@inject(({ market }) => ({ total: market.total }))
@observer
class TotalPrice extends Component {
render() {
const { total } = this.props;
return (
<div>
<hr />
<p>{total}</p>
</div>
);
}
}
export default TotalPrice;
MobX의 React 컴포넌트 최적화
-
리스트를 렌더링할 때는 컴포넌트에 리스트 관련 데이터만 Props로 넣는다.
-
세부참조는 최대한 내부의 컴포넌트에서 한다.
@observer
class MyComponent extends Component {
render() {
const { todos, user } = this.props;
return (
<div>
{user.name}
<ul>
{todos.map((todo) => (
<TodoView todo={todo} key={todo.id} />
))}
</ul>
</div>
);
}
}
위에서 user.name observable만 변경되어도 컴포넌트가 리렌더링되기 때문에, 리스트는 다음과 같이 따로 분리시키는 것이 좋다.
@observer
class MyComponent extends Component {
render() {
const { todos, user } = this.props;
return (
<div>
{user.name}
<TodosView todos={todos} />
</div>
);
}
}
@observer
class TodosView extends Component {
render() {
const { todos } = this.props;
return (
<ul>
{todos.map((todo) => (
<TodoView todo={todo} key={todo.id} />
))}
</ul>
);
}
}