MobX with React - 환경 구축과 적용

HADMARINE·2020년 2월 12일
4

MobX with React

목록 보기
2/2
post-thumbnail

환경 구축에 앞서

MobX의 기능 중 하나인 데코레이터(@)를 이용해서 적용하는 코드는 create-react-app 에서 공식적으로 지원하는 메서드가 아니에요.
그래서 이를 지원하게 하려면 babel 설정을 만져야 하는데, babel 설정을 만지려면 두가지 방법이 있습니다. 첫번째는 지독한 yarn eject, 두번째는 customize-crareact-app-rewired패키지를 이용하는 방법이 있어요.

저는 후자를 선택했습니다.

일단 첫번째로, 의존성 관리가 매우 매우 어렵다는 것입니다. yarn eject를 하고 Dependency 를 설치하면, 다른 패키지와의 의존성을 신경써야 패키지들끼리 충돌이 나지 않아요.
두번째로, 저희가 원하는 순기능이기도 하고, 역기능이 될 수도 있는, babel, webpack 설정을 바꿀 수 있는 기능입니다. 이도 마찬가지로 굉장히 복잡하므로, 필요한 설정만 수정하는 것이 아니면 저 뿐만 아니라 여러분의 생산성을 떨어뜨릴 것이 분명하기 때문이지요.

주의!

customize-crareact-app-rewired패키지를 이용한다고 해도 create-react-app 에서 기본적으로 지원되던 모든 기능이 정상적으로 동작하지 않을 수 있습니다.
하지만 yarn eject와는 다르게 되돌아갈 수 있으므로, 항상 그 부분을 염두에 두고 코드를 작성하세요.

환경 구축

데코레이터(@) 관련 환경 구축

앞서 말했듯, babel 설정을 만져줘야 하기 때문에, 해당 설정부터 먼저 만져주도록 해요.

yarn 사용자께서는 yarn 을 사용하시고, npm 사용자는 npm 을 사용하시면 됩니다. 두 스크립트를 둘 다 실행해야하는것은 아니에요.

React - eject 없이 Mobx 데코레이터 사용하기를 참고했어요.

1. 패키지를 설치해요.

[yarn]

yarn add --dev customize-cra react-app-rewired @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties core-decorators


[npm]

npm i --save -d customize-cra react-app-rewired  @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties core-decorators

2. package.json의 scripts를 수정해요.

package.json에 있는 scripts 중, eject에 있는 것을 제외한 모든 react-scripts 를 react-app-rewired 로 교체해요. 따로 설정해 놓으신 스크립트가 있으셔도 react-scripts 만 교체하시면 됩니다.

...
"scripts": {
	"start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject",
    ...
}
...

3. package.json에 babel 세팅을 추가해요

기존에 다른 세팅이 있으셨던 분은 현재 작성된 코드와 적절히 병합하시면 됩니다!

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

4. 프로젝트 파일 루트 폴더에 config-overrides.js를 추가해요.

const { 
  addDecoratorsLegacy,
  disableEsLint, // eslint를 끄는 것이 아니에요 ^^
  override,
} = require("customize-cra");

module.exports = {
  webpack: override(
      disableEsLint(),
      addDecoratorsLegacy()
  ),
};

5. tsconfig.json (혹은 jsconfig.json)에서 컴파일 옵션을 추가해요.

기존에 config 파일을 만들어두지 않으셨다면 프로젝트의 루트 디렉토리에 본인에게 맞는 config (Typescript 를 사용하고 계신다면 tsconfig.json, Javascript 를 사용하고 계신다면 jsconfig.json 이겠죠?) 를 생성하시면 됩니다.

{
  "compilerOptions": {
    ...
    "experimentalDecorators": true
    ...
  },
  ...
}

그리고 위와 같이 experimentalDecorators 를 true 로 설정해주시면 lint 상에서 오류가 발생하지 않아요.

MobX를 React 에 적용하기

MobX는 애초에 React에서 사용하기 위해 제작되었기 때문에 React에 적용하기가 굉장히 간편해요. 모듈 몇 개만 설치하고, 적용하면 끝! 타입스크립트도 신경 쓸 필요가 없습니다!

1. 패키지를 설치해요.

[yarn]

yarn add mobx mobx-react


[npm]

npm i --save mobx --save mobx-react

2. MobX 의 Store 를 저장할 stores를 생성해요

먼저, src 아래에 /stores 폴더를 생성한 뒤, 당신만의 스토어 파일을 생성해요.

저는 YourStore로 해볼게요.
참, 저는 타입스크립트를 사용하였습니다만 자바스크립트의 경우에도 코드가 거의 동일합니다.

코드를 작성해요.

YourStore.ts

import { observable, action } from 'mobx';

export default class YourStore {
  @observable yourStore = 'hello';

  @action changeStoreValue = (value: string) => {
    this.yourStore = value;
  };
  @action changeToWorld = () => {
  	this.yourStore = "World";
  }
}

위에서 볼 것은 두가지 인데요.

첫번째로 @observable 입니다. 이는 React 의 state 와 비슷한 역할을 하는데요. MobX상에서 변수의 역할을 하신다고 보면 됩니다. 따라서 MobX에서 변수를 선언하실 때에는 일반적인 var let const와 같은 키워드가 아닌, @observable 로 선언하셔야 합니다.

두번째로, @action 인데요. 이는 값을 변경해 줄 수 있는 메서드, 즉 React 에서의 setState 의 역할을 하신다고 보면 됩니다. 하지만 기존의 setState 와는 다르게 함수를 커스터마이징 할 수 있는데요. 예제코드처럼 changeToWorld를 호출하게 되면 yourStore 는 World 라는 값으로 바뀌게 됩니다. 이를 활용해서 여러분들만의 코드를 제작하실 수 있어요. 추후 에피소드에서 이와 관련된 Side-effects 에 관해서 다룰거에요.

3. 최상단 컴포넌트 (index.tsx) 에서 Provider 를 설정해줍니다.

import React from "react";
import ReactDOM from "react-dom";
...
import App from "./App";
import { Provider } from "mobx-react";
import YourStore from "./stores/YourStore";

const yourstore = new YourStore();

const RenderComponent = () => (
  <Provider yourstore={yourstore}>
    <App />
  </Provider>
);

ReactDOM.render(<RenderComponent />, document.getElementById("root"));

4. 하위 컴포넌트에서 props 에 inject 시켜줍니다.

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

@inject("yourstore")
@observer
export default class App extends React.Component<any> {
  render() {
    return (
      <div>
        <div>value = {this.props.yourstore.yourStore}</div>
        <div>
          <button onClick={this.props.yourstore.changeToWorld}>
            Change to world
          </button>
        </div>
      </div>
    );
  }
}

여기서 두 가지의 새로운 데코레이터 문법이 있는데요.
@inject 는 3번처럼 최상단 컴포넌트에서 Provider를 설정할 때 props로 준 store를 불러옵니다. 만약 Provider 에 props 로 a라는 props를 전달해 주었으면, @inject('a');로 불러와야 합니다. inject 를 하게 되면 a라는 props가 전달이 되며, a 안의 observable value 나 action을 불러와서 사용할 수 있습니다.

@observer는 해당 클래스를 watch (감시) 하여 값이 바뀌게 되면 this.forceUpdate() 를 트리거 해주겠다는 것입니다.

정상적으로 바뀌는군요!

정리

이제 MobX 를 통해 여러분의 코드를 훨씬 생산적으로 제작할 수 있습니다. 즐코딩!

Github 링크 에서 실제 적용된 코드 (타입스크립트)를 확인하실 수 있습니다.

profile
Abroad the world!

2개의 댓글

comment-user-thumbnail
2021년 3월 30일

감사합니다 ㅎㅎ 덕분에 깔끔하게 설치했네요!

1개의 답글