개요

mobX는 JavaScript application(특히 react)의 상태 관리 라이브러리이다.

mobX는 핵심적으로 observable한 object를 생성해서 그것의 변화를 추적한다. observable한 object가 변하면, 객체가 자동적으로 업데이트된다.

mobX의 핵심적인 특성은 반응하는 데이터 구조를 복잡한 API나 data에 대한 새로운 해석을 할 필요 없이 JavaScript 문법으로 정의할 수 있다는 것이다.

또한 mobX의 강력한 기능은 복잡한 어플리케이션의 상태를 action을 이용해 정의할 수 있다는 것이다. Actions는 어플리케이션의 상태를 변형하는데 필수적이다.

mobX는 application의 규모 또는 복잡도와 상관없이 powerful하고 flexible한 tool이다


MobX의 요지

개념

MobX의 어플리케이션 내 세 가지 개념

  1. 상태(state)

  2. 동작(action)

  3. 파생(derivation)

1. 상태(state)를 정의하고 관찰 가능하게(observable) 만들기

class Todo {
    id = Math.random()
    title = ""
    finished = false
    constructor(title) {
        makeObservable(this, {
            title: observable,
            finished: observable,
            toggle: action
        })
        this.title = title
    }
    toggle() {
        this.finished = !this.finished
    }
}

state는 애플리케이션을 구동하는 데이터. 원하는 데이터를 state에 저장하고 모든 속성을 mobX가 추적할 수 있도록 observable로 표시하면 된다.

toggle은 action이고 finished값(observable)을 변경시킨다.

2. action을 이용한 state 업데이트

위의 코드에서 toggle은 finished값(observable)을 변경시킨다. action은 사용자 이벤트, 백엔드 데이터 푸시, 예약된 이벤트와 같이 state를 변경하는 코드조각이다. 위의 예시처럼 observable을 변경하는 코드는 action으로 표시해두면 MobX가 트랜잭션을 자동으로 적용하여 성능을 쉽게 최적화 할 수 있다.

3. 상태(state) 변화에 자동으로 응답하는 파생(derivation) 만들기

derivation : state에서 더 이상의 상호작용 없이 파생될 수 있는 모든 것.

derivation의 두 종류

  • computed : observable state에서 순수 함수를 사용하여 파생될 수 있는 값
  • reaction : state가 변경될 때 자동으로 발생해야 하는 부수효과

3-1. computed를 사용하여 파생된 값 모델링

import { makeObservable, observable, computed } from "mobx"
class TodoList {
    todos = []
    get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.finished).length
    }
    constructor(todos) {
        makeObservable(this, {
            todos: observable,
            unfinishedTodoCount: computed
        })
        this.todos = todos
    }
}

3-2. reaction을 사용한 side effect 모델링

사용자가 화면에서 state의 변화나 computed 값의 변화를 볼 수 있으려면 GUI의 일부를 다시 그리는 reaction이 필요하다.

reaction은 computed 값과 유사하지만, 정보를 생성하는 대신 콘솔 출력, 네트워크 요청, DOM 패치 적용을 위해 React 컴포넌트 트리를 점진적으로 업데이트하는 등의 부수효과를 생성한다.

지금까지 가장 많이 사용되는 reaction 형태는 UI 컴포넌트이다. action과 reaction 모두 부수효과를 일으킬 수 있다. form을 제출할 때 네트워크 요청을 하는 것처럼, 트리거 될 수 있는 명확하고 명시적인 출처가 있는 부수효과는 관련 이벤트 핸들러에서 명시적으로 트리거 되어야 한다.

3-3 . 반응형 리액트 컴포넌트

const TodoListView = observer(({ todoList }) => (
    <div>
        <ul>
            {todoList.todos.map(todo => (
                <TodoView todo={todo} key={todo.id} />
            ))}
        </ul>
        Tasks left: {todoList.unfinishedTodoCount}
    </div>
))
const TodoView = observer(({ todo }) => (
    <li>
        <input type="checkbox" checked={todo.finished} onClick={() => todo.toggle()} />
        {todo.title}
    </li>
))
const store = new TodoList([
  new Todo("MobX 핵심기능 Confluence에 정리하기"),
  new Todo("Git의 여러 기능들 사용해보고 Confluence 정리하기 "),
  new Todo("카드등록 토스뱅크 체크카드 기준으로 마무리하기")
]);

위의 코드들 종합해서 만든 것

코드보기
import React from "react";
import {
  observable,
  action,
  makeObservable,
  computed
} from "mobx";
import { observer } from "mobx-react";
export default function App() {
  return (
    <div className="App">
      <TodoListView todoList={store} />
    </div>
  );
}
class Todo {
  id = Math.random();
  title = "";
  finished = false;
  constructor(title) {
    makeObservable(this, {
      title: observable,
      finished: observable,
      toggle: action
    });
    this.title = title;
  }
  toggle() {
    this.finished = !this.finished;
  }
}
class TodoList {
  todos = [];
  get unfinishedTodoCount() {
    return this.todos.filter((todo) => !todo.finished).length;
  }
  constructor(todos) {
    makeObservable(this, {
      todos: observable,
      unfinishedTodoCount: computed
    });
    this.todos = todos;
  }
}
const TodoListView = observer(({ todoList }) => (
  <div>
    <ul>
      {todoList.todos.map((todo) => (
        <TodoView todo={todo} key={todo.id} />
      ))}
    </ul>
    Tasks left: {todoList.unfinishedTodoCount}
  </div>
));
const TodoView = observer(({ todo }) => (
  <li>
    <input
      type="checkbox"
      checked={todo.finished}
      onClick={() => todo.toggle()}
    />
    {todo.title}
  </li>
));
const store = new TodoList([
  new Todo("MobX 핵심기능 Confluence에 정리하기"),
  new Todo("Git의 여러 기능들 사용해보고 Confluence 정리하기 "),
  new Todo("카드등록 토스뱅크 체크카드 기준으로 마무리하기")
]);

React에서 makeAutoObservable 사용

import React from "react";
import { makeAutoObservable } from "mobx";
import { observer } from "mobx-react";

export default function App() {
  return (
    <div className="App">
      <TimerView timer={myTimer} />
    </div>
  );
}

class Timer {
  secondsPassed = 0;

  constructor() {
    makeAutoObservable(this);
  }

  increase() {
    this.secondsPassed += 1;
  }

  reset() {
    this.secondsPassed = 0;
  }
}

const myTimer = new Timer();

// observable state를 사용하는 사용자 인터페이스를 구축합니다.
const TimerView = observer(({ timer }) => (
  <button onClick={() => timer.reset()}>
    Seconds passed: {timer.secondsPassed}
  </button>
));

// 매초마다 Seconds passed: X를 업데이트 합니다.
setInterval(() => {
  myTimer.increase();
}, 1000);

constructor에 makeAutoObservable을 넣고, TimerView를 observer로 감싸주어 timer.secondsPassed에 의존하여 값이 자동적으로 수정한다. 해당 예제는 onClick, setInterval 등의 이벤트가 있는데 ObservableState(myTimer.secondsPassed)를 변경시키는 myTimer.increase(), myTimer.reset()을 호출한다.

MobX의 원칙 - 단방향 데이터 흐름

1. state가 변경되면 모든 derivation이 자동으로 원자단위로 업데이트 됨.
2. derivation은 동기식으로 업데이트.
3. computed 값은 느리게 업데이트 → 활발히 사용되지 않는 값은 부수효과에 필요할 때 까지 업데이트 x
5. computed 값은 순수해야 하고, state를 변경시키면 안됨.

MobX 기본원칙

profile
최고의 효율을 창출하기 위해 겸손히 노력합니다.

0개의 댓글