3. MobX 가 리액트를 만나면

MobX 는 리액트 종속적이진 않지만, 리액트에서 쓰려고 만들어졌기 때문에 함께 사용하면 엄청난 시너지가 발생합니다. 더 쉬운 글로벌 상태 관리는 물론이고, setState 도 쓸 필요가 없게 됩니다.

우리가 이전 섹션에서 decorator 문법을 통해서 더 편하게 MobX 를 사용하는 방법을 배웠었는데요, 우리가 만약에 create-react-app 으로 프로젝트를 만들면 기본적으로는 decorator 를 사용하지 못하기 때문에 따로 babel 설정을 해줘야 합니다.

우선, decorator 없이 리액트에서 MobX 를 사용하는 방법을 알아볼게요!

프로젝트 준비하기

다음 명령어를 통해 평범한 리액트 프로젝트를 만들어주세요.

$ npx create-react-app mobx-with-react
$ cd mobx-with-react
$ yarn add mobx mobx-react
$ yarn start

카운터 만들기

MobX 를 사용해서 엄청나게 간단한 카운터를 만들어보겠습니다.

src/Counter.js

import React, { Component } from 'react';
import { decorate, observable, action } from 'mobx';
import { observer } from 'mobx-react';

class Counter extends Component {
  number = 0;

  increase = () => {
    this.number++;
  };

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

  render() {
    return (
      <div>
        <h1>{this.number}</h1>
        <button onClick={this.increase}>+1</button>
        <button onClick={this.decrease}>-1</button>
      </div>
    );
  }
}

decorate(Counter, {
  number: observable,
  increase: action,
  decrease: action,
});

export default observer(Counter);

다 만드셨으면 App.js 에 반영해주세요.

src/App.js

import React, { Component } from 'react';
import Counter from './Counter';

class App extends Component {
  render() {
    return (
      <div>
        <Counter />
      </div>
    );
  }
}

export default App;

Edit mobx-with-react

카운터가 잘 작동하는지 확인해보세요.

진짜 간단하죠..? 뭔가 리액트스럽지가 않습니다. setState 없이 그냥 값 바꿔주면 알아서 렌더링해줍니다. 어떻게 알아서 렌더링해주냐구요? 코드 최하단에서 사용된 observer 가 observable 값이 변할 때 컴포넌트의 forceUpdate 를 호출하게 함으로써 자동으로 변화가 화면에 반영됩니다.

이게 성능상으로 과연 좋을까 걱정이 될 수도 있긴 하지만 놀랍게도 최적화가 많이 되어있어서 그 부분에 대해서는 크게 걱정하실 필요없습니다.

이런식으로, 리액트에서 MobX 를 사용할 땐 리덕스에서 했던 것 처럼 따로 다른 파일로 스토어를 만들 필요도 없고 (필요하면 만들 수도 있습니다) 그냥 컴포넌트에 바로 적용해줄 수 있습니다.

Decorator 와 함께 사용하기

여기서, decorator 를 사용하면 훨씬 더 편하게 문법을 작성 할 수 있는데요, 그러려면 babel 설정을 해주셔야 합니다. babel 설정을 커스터마이징 하려면 yarn eject 를 해야합니다.

eject 없이 하고 싶다면 customize-cra 를 참고하세요.

$ yarn add @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators

그리고 나서, package.json 을 열으신 다음에, babel 쪽을 찾아서 다음과 같이 수정해주세요.

  "babel": {
    "presets": [
      "react-app"
    ],
    "plugins": [
        ["@babel/plugin-proposal-decorators", { "legacy": true}],
        ["@babel/plugin-proposal-class-properties", { "loose": true}]
    ]
  }

설정을 다 하셨으면, 개발서버를 껐다 켜주시고, Counter 코드를 decorator 로 더 깔끔하게 작성해보겠습니다.

src/Counter.js

import React, { Component } from 'react';
import { observable, action } from 'mobx';
import { observer } from 'mobx-react';

// **** 최하단에 잇던 observer 가 이렇게 위로 올라옵니다.
@observer
class Counter extends Component {
  @observable number = 0;

  @action
  increase = () => {
    this.number++;
  };

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

  render() {
    return (
      <div>
        <h1>{this.number}</h1>
        <button onClick={this.increase}>+1</button>
        <button onClick={this.decrease}>-1</button>
      </div>
    );
  }
}

// **** decorate 는 더 이상 필요 없어집니다.
// decorate(Counter, {
//   number: observable,
//   increase: action,
//   decrease: action
// })

// export default observer(Counter);
// **** observer 는 코드의 상단으로 올라갑니다.
export default Counter;

Edit mobx-with-react

어떤가요? decorator 문법을 사용하니까 조금 더 깔끔하지 않나요? 저는 그렇다고 생각하는데, 취향에 따라 싫을 수 도 있습니다. 우선 우리가 이 튜토리얼의 상단부에서 다뤘던것처럼 decorator 사용은 필수는 아니라는 점, 알아두세요!

results matching ""

    No results matching ""