React 개발에서 (내가 생각하기에) 가장 중요한 개념은 상태 관리이고,
상태 관리를 가장 효율적으로 구현할 수 있는 제3사 라이브러리가 바로 Mobx이다.
(Redux는... Mobx보다 5~6배 인지도가 더 높고 더 많이 사용되고 있지만, 어휴... 그건 영... 아니다.)
>> 참고: www.npmtrends.com/react-redux-vs-mobx-react
상태 관리의 핵심은 props와 state를 이용하여 언제 어떻게 UI를 갱신할 것인가 하는 문제이다.
즉, 여기 저기 흩어져 있는 코드에서 상태를 변경할 경우에 상태 변경 때마다 UI를 갱신할 것인지,
아니면 상태를 모두 변경하고 마지막에 한번만 UI를 갱신할 것인지를 처리하는 문제라고 생각하면 편하다.
React에서는 기본적으로 state가 변경되면(setState 호출 시) render( ) 함수가 호출되면서 UI가 갱신되는데,
만들다 보면 state가 여기저기에서 이런 저런 이유로 두서없이 막 변경되어야 할 때도 있고
또, api/store/screen 단위로 분산 코딩을 한 경우에는 컴포넌트 내부 데이터가 아닌 외부 데이터가 변경됨에 따라
UI가 변경되어야 할 때도 있다. 이럴 때 setState( ) 만으로는 제대로 처리하기 어렵고 복잡한 경우가 많다.
Mobx를 사용하면 @observable과 @observer 데코레이터를 사용하는 것만으로 컴포넌트 내부에 state에 변수를 추가하고 setState( )를 호출하는 것과 동일한, 즉 상태 변화를 일으켜 UI를 갱신하는 효과를 자동으로 낼 수 있다.
즉, 컴포넌트 내부든 외부든 어디에서든 변수가 @observable로 지정되기만 하면
또, 해당 변수가 @observer로 지정된 클래스(컴포넌트)의 render( ) 내부에서 사용되는 경우라면,
그 변수값이 변경될 때 자동으로 UI가 갱신되는 메커니즘이다.
(해당 변수가 state에 포함된 후 setState( )가 호출되는 상황이라고 생각하면 된다. 내부적으로는 그렇다.)
인터넷에 널린 게 mobx 강좌에다 샘플이니... 쓸 데 없는 TMI 설명은 생략하고,
여기서는 CRA(create-react-app)으로 생성한 React 프로젝트에서 Mobx를 사용하는 방법과 절차를 알아보도록 한다.
1. CRA(create-react-app) 생성
먼저, 최신 CRA 4.0.1 이상 버전에서는 갑자기 더 이상 npx 명령어로 CRA 프로젝트를 생성할 수 없게 되었다.
(왜 이렇게 자꾸 되던 걸 안되게 변경하는지 증~~말 이해가 안되긴 한다)
% npx create-react-app react.test // 오류 발생 -->
% yarn create react-app react.test // CRA 4.0.1 설치
% cd react.test
yarn 명령으로 생성하면 이상없이 잘 된다.(이하 yarn 명령어를 계속 사용한다. 설치는 여기.)
(또는 create-react-app를 전역으로 재설치해 주면 npx 명령어로도 된다고는 하는데... 난 애초에 CRA 전역 설치가 안되어 있어서 시도해 보지 않아 모르겠다. 여기를 참조해 보면 될 것 같다.)
2. eject 결정
CRA로 생성한 React 프로젝트는 기본적으로 webpack과 babel, jest, eslint, sass 등이 특정 안정화 버전 기준으로 포함되어 기본 설정으로 적용되어 있고, 이 패키지들에 대한 설정들은 수정이 불가능한 상태이다. 즉, .eslintrc.js 파일이나 jsconfig.json, .babelrc 등을 만들어봤자 해당 설정들이 안 먹는다.
Mobx를 직관적이고 손쉬운 방식, 즉 위에서 언급했던 @observable, @observer 데코레이터 방식으로 사용하려면 몇 가지 babel 추가 기능(클래스 속성, 데코레이터 등)을 활성화해야 하는데 이를 위해서는 CRA를 eject하여 숨겨진 전체 패키지들이 package.json에 모두 명시적으로 포함되도록 하거나, 아니면 CRA 커스터마이징 지원 패키지를 추가 설치하는 방법을 사용해야 한다.
eject를 하면 webpack, babel, jest, eslint, sass 등의 패키지 버전을 수동으로 직접 관리해야 하는데 모바일 생태계 특성상 엄청나게 빠르게 변하기 때문에 조금만 시간이 지나도 프로젝트 빌드 자체가 되지 않는 매우 심각한 문제가 발생할 수 있다. 물론 그런 경우에 참조 패키지들 버전을 하나 하나 확인해 가며 다시 수정하면 되기야 하지만 이게 엄청난 스트레스가 된다.
최신 버전에서는 eject후 아래와 같은 빌드 오류가 발생하는데...
Cannot find module 'babel-plugin-syntax-jsx' |
또는
Cannot find module '@babel/plugin-transform-react-jsx' |
이 경우, 아래와 같이 @babel/plugin-transform-react-jsx 패키지를 추가 설치해 주어야 한다.
% yarn add @babel/plugin-transform-react-jsx
어쨌든, eject를 할 때와 하지 않을 때의 장·단점이 거의 50:50으로 비슷하기 때문에 필요에 의한 결정을 하면 되고... 한 가지, 다른 이유가 아니라면, Mobx를 사용하기 위해 eject를 할 필요는 없다.
>> 참조1: how to use mobx with create-react-app without run eject
>> 참조2: React - eject 없이 Mobx 데코레이터 사용하기 (velog.io)
위 두 참조 URL에 eject를 하지 않고 babel 설정을 수정/확장할 수 있도록 하는 방법이 잘 나와 있다. (둘 다 내용은 동일)
그대로 따라하면 된다.
3. babel 확장(플러그 인): 클래스 속성, 데코레이터 제안
Mobx를 설치하기 전에 먼저 ES6 이후 스펙에 추가된 데코레이터와 클래스 속성을 사용할 수 있도록 패키지 추가 및 설정 추가 작업을 해야 한다.
이것 역시 위 참조2 URL을 비롯하여 각종 사이트에 수없이 나와 있지만, 다시 한번 써 보면 아래와 같다.
% yarn add @babel/plugin-proposal-class-properties --dev
% yarn add @babel/plugin-proposal-decorators --dev
위 명령어로 babel 확장 플러그 인을 설치한 다음에 package.json 파일에 아래와 같이 설정을 추가/편집하거나,
...
"babel": {
"presets": [ "react-app" ],
"plugins": [
[ "@babel/plugin-proposal-decorators", { "legacy": true } ],
[ "@babel/plugin-proposal-class-properties", { "loose": true } ]
]
}
...
아니면 별도 .babelrc 파일을 생성한 다음 아래와 같이 설정을 추가하면 된다.
{
"presets": [ "react-app" ],
"plugins": [
[ "@babel/plugin-proposal-decorators", { "legacy": true } ],
[ "@babel/plugin-proposal-class-properties", { "loose": true } ]
]
}
중복으로 들어가지만 않는다면, 동작하는 건 동일하다.
4. ESLint 설정: 데코레이터 사용 추가
여기서 끝이 아니다. ESLint 설정에도 하나 더 추가해 줘야 데코레이터 사용 시 컴파일 오류가 발생하지 않는다.
역시 package.json 파일의 다음 부분을 추가/편집하거나,
...
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
],
"parserOptions": {
"ecmaFeatures": {
"legacyDecorators": true
}
}
},
...
별도 파일 .eslintrc.js 파일을 추가하고 아래와 같이 설정하면 된다.
module.exports = {
extends: [
"react-app",
"react-app/jest"
],
parserOptions: {
ecmaFeatures: {
legacyDecorators: true
}
}
};
추가로, Visual Studio에서 데코레이터 사용 시 경고가 발생하지 않도록 하기 위해 jsconfig.json 파일에 아래 설정을 추가하라고는 하는데... 이건 별로 효과도 없고, 필요도 없는 것 같다. 경고야 뭐 무시하면 되니까.
{
"compilerOptions": {
"experimentalDecorators": true
}
}
5. Mobx 설치
이제서야 본론으로 왔다. 마지막으로 Mobx를 설치하면 되는데, 이게 또 골때린다.
현재 시점(2020-11-28)에 아래 명령으로 최신버전으로 설치를 하게 되면,
% yarn add mobx mobx-react // mobx@6.0.4, mobx-react@7.0.5
위 주석을 달아놓은 것과 같이 mobx는 6.0.4 버전, mobx-react는 7.0.5 버전이 설치되는데
이게... 정상적으로 동작하지 않는다.
즉,
@observable을 아무리 변경시켜도 @observer의 render( )가 호출이 되지 않는 것.
혹시 코드를 잘못 쓴 건 아닌지, 다른 방식으로도 고쳐보고, 웹에서 샘플 코드도 찾아서 써 보고, 기존에 잘 동작하던 코드를 가져다가 써 보기도 하고... 별 짓을 다 해봐도 안됐다. 이틀, 만으로는 24시간을 이것 때문에 날려 먹었다.
하다 하다 마지막으로, 기존에 잘 동작했던 mobx 버전으로 내려봤다.
(mobx: 5.14.2, mobx-react: 6.1.4)
% yarn remove mobx mobx-react
% yarn add mobx@5.14.2 mobx-react@6.1.4 mobx-persist@0.4.1
헐... 이틀간 속썩이던 코드가 잘만 동작한다.
결국 이것도 Mobx 버전 호환성 문제였던 것.
좌우지간 모바일 라이브러리는 검증된 버전을 사용해야지,
절대 최신 버전이라고 막 갖다쓰면 안된다는 것을 다시 한번 깨달았다.
Mobx같이 훌륭한 패키지는 아예 안정화 버전을 CRA에 포함시켜두면 안되나?
CRAM(create-react-app-with-mobx) 정도로 이름 붙여서 누가 하나 만들어줬으면 좋겠다.
마지막으로 React에서 Mobx를 사용하기 위한 yarn 명령어를 두 가지 버전으로 묶어봤다.
(bootstrap, reactstrap은 매우 편리한 UI 라이브러리라 포함시켜 봤다.)
(jquery는 말할 필요도 없고...)
(cross-env와 rimraf는 개발/테스트 옵션으로 사용하기 편리해서 --dev 옵션으로 포함시켜 봤다.)
(nanoid는 id/key 생성 시에 매우 유용한 도구라 포함시켜 봤다.)
(axios는 fetch를 대체할 만한 훌륭한 REST API 도구다.)
[eject 버전]
% yarn create react-app react.test // CRA 4.0.1 설치
% cd react.test
% yarn eject
% yarn add @babel/plugin-transform-react-jsx
% yarn add @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators cross-env rimraf --dev
% yarn add jquery nanoid axios bootstrap reactstrap mobx@5.14.2 mobx-react@6.1.4 mobx-persist@0.4.1
[CRA pure 버전]
% yarn create react-app react.test // CRA 4.0.1 설치
% cd react.test
% yarn add customize-cra react-app-rewired --dev
% yarn add @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators cross-env rimraf --dev
% yarn add jquery nanoid axios bootstrap reactstrap mobx@5.14.2 mobx-react@6.1.4 mobx-persist@0.4.1
끝.
'Tech: > 일반·기타' 카테고리의 다른 글
React: reactstrap-Tooltip의 scheduleUpdate 함수?! (0) | 2020.12.07 |
---|---|
Visual Studio 2019로 React 개발/디버깅 #3 (0) | 2020.11.30 |
React: Tic-Tac-Toe 자습서 구현 예제 (1) | 2020.11.23 |
Visual Studio 2019로 React 개발/디버깅 #2 (0) | 2020.11.23 |
Visual Studio 2019로 React 개발/디버깅 #1 (0) | 2020.11.19 |