기본 사용법

기본 사용법부터 익혀보겠습니다. 한번, 카운터를 MobX 로 구현해볼까요?

MobX 는, 단순한 상태관리 라이브러리이기 때문에 무조건 글로벌 스토어를 만들 필요는 없습니다. 컴포넌트 내부에 내장 시킬 수도 있어요.

글로벌 스토어로 따로 빼내는것은 나중에 하고, 우선 컴포넌트 내부에서 MobX 를 바로 적용하는 방법을 알아보겠습니다.

카운터 구현하기

src/containers/CounterContainer.js

import React, { Component } from 'react';
import Counter from '../components/Counter';
import { observer } from 'mobx-react';
import { observable } from 'mobx';

@observer
class CounterContainer extends Component {
  @observable number = 0;

  handleIncrement = () => {
    this.number += 1;
  };

  handleDecrement = () => {
    this.number -= 1;
  };

  render() {
    const { number, handleIncrement, handleDecrement } = this;
    return (
      <Counter
        number={number}
        onIncrement={handleIncrement}
        onDecrement={handleDecrement}
      />
    );
  }
}

export default CounterContainer;

여기서 Decorator 문법이 사용됐습니다. (참고)

만약에 Decorator 를 사용하지 않는다면,

number = observable(0)
export default observer(CounterContainer)

의 형태로 구현 할 수 있습니다.

이렇게 이해하시면 쉽습니다:

  1. observer: 감시자
  2. observable: 감시받는 값

observable 값을 사용하는 컴포넌트에서는, 위에 저렇게 @observer 을 넣어주면 됩니다.

그럼 이걸 App 에서 렌더링하고 잘 작동하는지 확인해보세요.

재미있는점은, 우리가 setState 같은걸 사용하지 않는 다는 것 입니다. 마치, 불

투두리스트 구현하기

우선 우리가 더 이상 Immutable 을 사용하지 않을테니, Immutable 관련 코드를 Todos.js 에서 없애고, Todos 컴포넌트에서 우리가 나중에 전달 할 observable 배열을 사용 할 것이므로 observer 로 감싸줍니다.

src/components/Todos.js

import React from 'react';
import { observer } from 'mobx-react';

const TodoItem = ({ id, text, checked, onToggle, onRemove }) => (
  <li 
    style={{
      textDecoration: checked ? 'line-through' : 'none'
    }} 
    onClick={() => onToggle(id)}
    onDoubleClick={() => onRemove(id)}>
    {text}
  </li>
)

const Todos = ({todos, input, onInsert, onToggle, onRemove, onChange }) => {

  const todoItems = todos.map(
    todo => {
      const { id, checked, text } = todo;
      return (
        <TodoItem
          id={id}
          checked={checked}
          text={text}
          onToggle={onToggle}
          onRemove={onRemove}
          key={id}
        />
      )
    }
  )
  return (
    <div>
      <h2>오늘 할 일</h2>
      <input value={input} onChange={onChange}/>
      <button onClick={onInsert}>추가</button>
      <ul>
        { todoItems }
      </ul>
    </div>
  );
};

Todos.defaultProps = {
  todos: [
    {
      id: 0,
      text: '걷기',
      checked: false
    },
    {
      id: 1,
      text: '코딩하기',
      checked: true
    }
  ],
  input: ''
};

export default observer(Todos);

이제 컨테이너 컴포넌트를 만들어봅시다!

src/containers/TodosContainer.js

import React, { Component } from 'react';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
import Todos from '../components/Todos';

@observer
class TodoList extends Component {
  @observable
  todos = [
    {
      id: 0,
      text: '리덕스도 배웠으면',
      checked: true
    },
    {
      id: 1,
      text: 'MobX 도 배워보는건 어떨까',
      checked: false
    }
  ];
  id = 2;

  @observable input = '';

  handleChange = e => {
    this.input = e.target.value;
  };

  handleInsert = e => {
    this.todos.push({
      id: this.id++,
      text: this.input,
      checked: false
    });
    this.input = '';
  };

  handleToggle = id => {
    const todo = this.todos.find(todo => todo.id === id);
    todo.checked = !todo.checked;
  };

  handleRemove = id => {
    const todo = this.todos.find(todo => todo.id === id);
    this.todos.remove(todo); // 여기서 사용된 remove 는 MobX 의 함수입니다.
    // 참고: https://mobx.js.org/refguide/array.html#observable-arrays
  };

  render() {
    return (
      <div>
        <Todos
          todos={this.todos}
          input={this.input}
          onChange={this.handleChange}
          onInsert={this.handleInsert}
          onToggle={this.handleToggle}
          onRemove={this.handleRemove}
        />
      </div>
    );
  }
}

export default TodoList;

그리고 이걸 App 에서 렌더링하세요.

src/App.js

import React, { Component } from 'react';
import AppTemplate from './AppTemplate';
import CounterContainer from '../containers/CounterContainer';
import TodosContainer from '../containers/TodosContainer';

class App extends Component {
  render() {
    return (
      <AppTemplate
        counter={<CounterContainer />}
        todos={<TodosContainer />}
      />
    );
  }
}

export default App;

재밌지 않나요? 불변성에 대해서 신경쓰지 않아도 모든게 제대로 작동합니다. 불변성을 지키지는 않기 때문에, shouldComponentUpdate 를 통한 최적화는 하지 못합니다. 그 대신에, 다른 방식으로 최적화를 합니다 (참고)

results matching ""

    No results matching ""