스토어의 분리

자 이제 우리가 만든 상태들을 글로벌 스토어로 분리해보겠습니다. 컴포넌트에 종속되어있는 것이 아니라, 밖으로 꺼내서 여기저기서 사용 하기 쉽도록 해주는 것이죠!

리덕스와 다른점은 스토어가 여러개가 될 수 있다는 점 입니다.

그리고, 스토어끼리 교류를 할 수 있게 하기 위해서 루트 스토어를 만들기는 합니다.

루트 스토어는 이런식으로 만듭니다. (참고)

카운터 전용 스토어 만들기

스토어를 만들어봅시다! 기존의 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;

끝났습니다!

results matching ""

    No results matching ""