스토어의 분리
자 이제 우리가 만든 상태들을 글로벌 스토어로 분리해보겠습니다. 컴포넌트에 종속되어있는 것이 아니라, 밖으로 꺼내서 여기저기서 사용 하기 쉽도록 해주는 것이죠!
리덕스와 다른점은 스토어가 여러개가 될 수 있다는 점 입니다.
그리고, 스토어끼리 교류를 할 수 있게 하기 위해서 루트 스토어를 만들기는 합니다.
루트 스토어는 이런식으로 만듭니다. (참고)
카운터 전용 스토어 만들기
스토어를 만들어봅시다! 기존의 store 디렉토리를 지우고, stores 라는 디렉토리를 src 에 생성해고 내부에 counter.js 를 만드세요.
src/stores/counter.js
import { observable, action } from 'mobx';
export default class CounterStore {
constructor(root) {
this.root = root;
}
@observable number = 0;
@action
increase = () => {
this.number++;
};
@action
decrease = () => {
this.number--;
};
}
여기서 사용된 @actions 는 해당 메소드가 값을 바꾼다는것을 명시하며, 이를 통하여 개발자도구에서도 유용하게사용 할 수 있고, 성능적으로 개선을 해줍니다 (예: 여러개의 액션이 동시에 들어오면, 올바른 순서로 변화를 합쳐서 일으킴)
투두리스트 전용 스토어 만들기
이번엔 투두리스트에서 사용할 스토어를 만들어볼까요?
src/stores/todos.js
import { observable, action } from 'mobx';
export default class TodosStore {
@observable
todos = [
{
id: 0,
text: '리덕스도 배웠으면',
checked: true
},
{
id: 1,
text: 'MobX 도 배워보는건 어떨까',
checked: false
}
];
@observable input = '';
id = 2;
@action
create(text) {
this.todos.push({
id: this.id++,
text: text,
checked: false
});
}
@action
toggle(id) {
const todo = this.todos.find(todo => todo.id === id);
todo.checked = !todo.checked;
}
@action
remove(id) {
const todo = this.todos.find(todo => todo.id === id);
this.todos.remove(todo);
}
@action
setInput(input) {
this.input = input;
}
constructor(root) {
this.root = root;
}
}
상태 관련 로직을, 다 빼왔습니다!
루트 스토어 만들고 프로젝트에 적용하기
루트 스토어를 만들어봅시다!
src/stores/index.js
import CounterStore from './counter';
import TodosStore from './todos';
export default class RootStore {
constructor() {
this.counter = new CounterStore(this);
this.todos = new TodosStore(this);
}
}
그리고, 프로젝트에 적용하겠습니다. Redux 처럼 Provider 라는 컴포넌트를 사용해서 적용합니다.
src/Root.js
import React from 'react';
import { Provider } from 'mobx-react';
import App from './components/App';
import RootStore from './stores';
const store = new RootStore();
const Root = () => {
return (
<Provider {...store}>
<App />
</Provider>
);
};
export default Root;
하나만의 스토어를 설정하는 리덕스와 달리 MobX 에서는 여러개를 설정 할 수 있습니다. 다음과 같이 말이죠:
<Provider counter={counter} todos={todos}>
여기서 {...store} 를 한건, 위와 동일한 코드입니다. 자신이 들고있는 모든 스토어를 props 로 뿌려준것이죠!
카운터 컨테이너 수정하기
Provider 를 통해 글로벌 상태를 넣어주고 나면, inject 를 통하여 값을 넣어줄 수 있습니다. 그리고 observer 는 동일하게 적용해주어야 합니다.
src/containers/CounterContainer.js
import React, { Component } from 'react';
import Counter from '../components/Counter';
import { observer, inject } from 'mobx-react';
@inject(stores => {
return {
number: stores.counter.number,
increase: stores.counter.increase,
decrease: stores.counter.decrease
};
})
@observer
class CounterContainer extends Component {
handleIncrement = () => {
this.props.increase();
};
handleDecrement = () => {
this.props.decrease();
};
render() {
const { number } = this.props;
const { handleIncrement, handleDecrement } = this;
return (
<Counter
number={number}
onIncrement={handleIncrement}
onDecrement={handleDecrement}
/>
);
}
}
export default CounterContainer;
투두리스트 컨테이너 수정하기
투두리스트 컨테이너도 수정해봅시다!
src/containers/TodosContainer.js
import React, { Component } from 'react';
import { observer, inject } from 'mobx-react';
import Todos from '../components/Todos';
@inject('todos')
@observer
class TodoList extends Component {
handleChange = e => {
const { todos } = this.props;
todos.setInput(e.target.value);
};
handleInsert = e => {
const { todos } = this.props;
todos.create(todos.input);
todos.setInput('');
};
handleToggle = id => {
const { todos } = this.props;
todos.toggle(id);
};
handleRemove = id => {
const { todos } = this.props;
todos.remove(id);
};
render() {
const { todos } = this.props;
return (
<div>
<Todos
todos={todos.todos}
input={todos.input}
onChange={this.handleChange}
onInsert={this.handleInsert}
onToggle={this.handleToggle}
onRemove={this.handleRemove}
/>
</div>
);
}
}
export default TodoList;
끝났습니다!