본문 바로가기

React

MobX | React와 MobX로 카운터 만들기

새로운 기술에 가장 빠르고 또 가까이 다가갈 수 있는 방법은 결국 직접 활용해서 무언가를 만들어 보는 것이라 생각한다.

앞서 이론 중심으로 소개했던 MobX를 활용한 간단한 예제를 만들어보자.

 

 

위와 같은 아주 원초적인 UI의 Counter를 (1)React만 사용해 구현해보고 (2)MobX를 사용하는 형태로 바꾸어볼 예정.


(1) React로만 Counter 구현하기

Counter 컴포넌트 구현

//Counter.jsx

import React, { useState } from "react";

const Counter = () => {
  const [num, setNum] = useState(0);

  //숫자 +1
  const increaseNum = () => {
    setNum(num + 1);
  };

  //숫자 -1
  const decreaseNum = () => {
    setNum(num - 1);
  };

  return (
    <div style={{ textAlign: "center" }}>
      <h1>{num}</h1>
      <button onClick={increaseNum}>+1</button>
      <button onClick={decreaseNum}>-1</button>
    </div>
  );
};

export default Counter;

 

숫자(state), 증가 함수, 감소 함수를 포함하는 간단한 컴포넌트를 만들었다.

여기서 주목해야 할 부분은 바로 state ! MobX를 통해 가장 크게 변하게 될 부분이다.

 

(2) React + MobX 를 활용한 Counter 구현하기

MobX 설치

$ yarn add mobx mobx-react

위 명령어를 통해 mobx, mobx-react를 설치한다.

여기서 mobx-reac는 React MobX의 사용을 도와주는 3rd party 라이브러리로, class와 hooks를 모두 지원한다.

hooks만 지원하는 또다른 라이브러리로는 mobx-react-lite 가 있다.

 

 

Store 구축 / observable state 만들기

Store는 컴포넌트의 로직과 state를 독립적으로 분리해 프론트엔드 및 백엔드에서 사용할 수 있도록 한다.

별개로 떨어져있어 재사용이 쉽고 유지보수도 용이하다는 이점이 있다.

 

MobX에 대한 자료를 검색하다보니 불과 3-4년 전만해도 아래와 같이 데코레이터(* velopert님 표현을 인용하자면, 자바스크립트의 사투리격)를 활용해 Store를 구축하는 경우가 많았다.

 

import { observable, action } from 'mobx';

export default class CounterStore {

  //observable 데코레이터를 통해 추적 가능한 state로 만들어준다.
  @observable 
  number = 0;

  //action 데코레이터를 통해 observable state를 변경하는 action 함수로 만들어준다.
  @action
  increase = () => {
    this.number++;
  };

  @action
  decrease = () => {
    this.number--;
  };
};

 

하지만 기술의 변화는 빠르디 빠르고..

MobX 6부턴 데코레이터없이도 React의 컴포넌트에서 렌더링될 state로 사용되는 Observable State를 지정할 수 있다. 바로 makeObservable와 makeAutoObservable를 사용하는 것.

 

makeObservable은 존재하는 객체 속성을, makeAutoObservable은 가지고 있는 모든 속성을 observable로 지정한다. 아래 예제 코드에선 makeAutoObservable 을 사용했다.

 

//store/CounterStore.js

import { makeAutoObservable } from "mobx"; 

class CounterStore {
  constructor() {
  //추적 가능한 state 정의
    makeAutoObservable(this);
  }

  // 숫자
  number = 0;

  // 숫자+1
  increase = () => {
    this.number++;
  };

  // 숫자-1
  decrease = () => {
    this.number--;
  };
}

export default CounterStore;

 

자, 이제 CounterStore Class 안의 모든 속성은 observable로 지정되어 MobX의 관찰을 받게 된다.

 

 

index.js

import React from "react";
import ReactDOM from "react-dom/client";

import CounterMobX from "./CounterMobX";
import CounterStore from "./store/CounterStore";

//Store의 인스턴스 생성
const Store = new CounterStore();

const rootNode = document.getElementById("root");

ReactDOM.createRoot(rootNode).render(
  <React.StrictMode>
    <CounterMobX counter={Store} />
  </React.StrictMode>
);

 

앞서 store에서 만든 Class의 인스턴스를 생성하고, CounterMobx 컴포넌트에 내려준다.

 

 

Counter 컴포넌트 구현

//CounterMobX.jsx

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

// 컴포넌트를 observer로 감싸주어서 state의 변경을 실시간으로 추적할 수 있다.
const CounterMobX = observer(({ counter }) => {
  return (
    <div style={{ textAlign: "center" }}>
      <h1>{counter.number}</h1>
      <button onClick={counter.increase}>+1</button>
      <button onClick={counter.decrease}>-1</button>
    </div>
  );
});

export default CounterMobX;

 

Counter.jsx 컴포넌트와 동일한 기능을 가졌지만 MobX를 사용하면서 state가 사라진 형태의 컴포넌트가 탄생했다.

컴포넌트 전체를 observer로 감싸주었기 때문에 observable state의 변경을 실시간으로 감지할 수 있고,

그 state는 분리된 Store에 위치해있다.


업무를 하면 할수록 상태관리의 필요성을 느끼고있는데, Redux에 비해 간결하고 깔끔한 코드를 가지고 있고 로직 분리를 통해 보다 객체 지향적으로 상태 관리를 할 수 있는 MobX는 앞으로도 자주 사용하게 될 것 같다.  지금은 아주 간단한 카운터에 활용하지만 점차 더 복잡한 데이터를 다룰 수 있겠지!

 

참고 학습자료
MobX 공식문서