MobX
MobX
MobX와 React Context를 모두 사용하여 [store -> context(provider), useHoC -> container] 구조로 사용 중
:: HoC? High-order Component
- 벨로퍼트 - 리액트 Context API 파헤치기
- 예제에서는 context, useHoc -> container 만 사용
- https://mobx.js.org/getting-started
- 기본 개념. 상태 변화 감지. Store, Observer 개념
- 예제에서는 Store, Container(View) 만 사용
- https://ko.mobx.js.org/react-integration.html
- 더 상세한 설명. code snippet 등등... 대체로 여기서(좌측 메뉴들) 찾아보면 됨.
- React context, Provider 관련 부분에 대한 설명
- https://ko.mobx.js.org/react-optimizations.html
- 잘못 사용하는 경우 & Best Practice에 대한 설명. 내용도 짧으니까 꼭 참고할 것.
---
MobX가 왜 필요한가?
- MobX는 React에 종속적이지 않은 독립적으로 사용 가능한 라이브러리다. (하지만 대체로 React와 함께 사용한다.)
- observer가 observable 지정된 state를 감시하다가, state에 변화가 생기면 re-render한다.
- vanilla React는 setState를 사용해야 하지만, MobX에서는 이를 사용하지 않는다. 알아서 observer가 observable을 관찰하고 re-render 한다.
- observable은 도메인 객체, observer는 이를 감시하는 액터라고 생각하면 된다.
- each component individually re-renders when relevant data changes.
- MobX를 사용할 때, observer가 안붙으면, 해당 react component에서 참조하고 있는 변수(state)에 변화가 생겨도 re-render가 일어나지 않는다. (re-render만 안될 뿐 함수 호출이라던지 나머지는 동작함)
헌데 생각해보면 React만 사용해도 state가 변경되면 그를 참조하고 있는 컴포넌트(view)가 re-render 된다.
단지 observable의 re-render만 필요한 거 였다면 그냥 리액트 써도 될텐데, 왜 MobX가 필요한 것일까?
MobX나 Redux는 "state 관리 라이브러리" 다.
상태 관리 라이브러리란, 말 그대로 state를 쉽게 관리하도록 지원하는 라이브러리다.
- 특히 React만으로는 처리하기 어려웠던 글로벌 상태 관리(context)를 지원
- 상태 업데이트 로직 분리 가능
- 더 손쉬운 상태 관리 (라이브러리 코드 스타일. 개발 방식) - setState 걷어내기
- 성능 : state 변경 시 발생하는 re-render 최적화
- 미들웨어 등 (Redux의 경우)
(1) 이전에는 글로벌 상태 관리 하나만으로도 가치가 있었는데, React가 Context API를 지원하기 시작하면서 React 만으로도 글로벌 상태 관리가 가능해졌다.
그래서 단순히 글로벌 상태만 사용하려는 목적이라면 Context API만으로도 커버가 되나, 상태 관리 라이브러리가 글로벌 상태 관리만 제공하는 것은 아니다.
(2) useReducer로도 가능하다. 하지만 코드 스타일이 마음에 안들 수 있음.
(4) yobi [공유] 스마트에디터 React, MobX 개선 사례 , 벨로퍼트 - 리덕스 잘 쓰고 계시나요?
- React.Component를 예로 들면, 컴포넌트가 re-render 되어야 하는지를 shouldComponentUpdate 리턴값을 보고 판단함.
- 이를 구현하지 않는 경우 컴포넌트는 항상 재 렌더링을 하게 됨 (props, state 변경 사항이 없는 경우에도 re-render)
- MobX observer를 사용하면 변경이 있는 경우에만 re-render 하므로 효율적임. (물론 다른 방법을 사용할 수도 있다)
The observer HoC automatically subscribes React components to any observables that are used during rendering.
As a result, components will automatically re-render when relevant observables change. It also makes sure that components don't re-render when there are no relevant changes. So, observables that are accessible by the component, but not actually read, won't ever cause a re-render.
MobX reacts to any existing observable property that is read during the execution of a tracked function(observer).
https://ko.mobx.js.org/understanding-reactivity.html
이 밖에도 setState로 인한 다양한 문제점이라던지.. MobX를 사용했을 때의 장점은 찾아보면 많이 나온다.
https://simsimjae.tistory.com/448
MobX 어떻게 사용해야 하나
observer와 observable은 항상 사용하면 되는건가?
You might be wondering, when do I apply observer? The rule of thumb is: apply observer to all components that read observable data.
Usually all your components should be wrapped by observer. Don't worry, this is not inefficient. On the contrary, more observer components make rendering more efficient as updates become more fine-grained.
observer 내에 observable이 어떤 출처로 왔는지, 어떻게 전달되었는지는 상관없다. 하지만 React Context를 사용해 전달하는 것을 추천
- For observer to work, it doesn't matter how the observables arrive in the component, only that they are read.
- props로 전달받았든, 전역으로 직접 참조하든, React Context를 사용해 전달받았든 상관없다.
- 하지만 external state의 경우 React Context를 사용해 전달하는 것을 추천한다.
- React Context is a great mechanism to share observables with an entire subtree
- 또는!! observable을 로컬에 한정한 state로 만들어서 사용하는 것도 가능.
observer가 아닌 컴포넌트에 observable을 넘기지 마라
- https://ko.mobx.js.org/react-integration.html#dont-pass-observables-into-components-that-arent-observer
- 전달해야 한다면 observable내의 plain js value를 전달 하거나, plain js object로 바꿔서 전달.
너무 빨리 필드를 풀어서 전달할 필요는 없다 (역참조는 최대한 늦게 해라)
```js
Slower : <DisplayName name={person.name} />
Faster : <DisplayName person={person} />
```
- (중요) MobX는 observable 값이 변경 되었을 때, 해당 값을 참조(referencing)하고 있는 컴포넌트들을 모두 re-render 하기 때문임.
- 매우 중요. 참조 하는 것 만으로도 re-render 대상이 되기 때문에 불필요한 re-render가 발생 할 수 있음.
- computed를 활용하자. 스마트에디터 개선 사례 참조
- computed는 값을 캐싱하고 있다가 내부 값에 변경이 발생하면 body를 실행하며 캐시를 갱신함
- person.name은 여기서 쓰이는 코드가 아닌데 풀어서 전달했다고 가정하자.
- 그냥 person 넘겨도 상관 없는 상황. 즉 person.name이 변경되었을 때 현위치 컴포넌트는 re-render 될 필요가 없는 상황임.
- 이 때 만약 person.name이 변경된다면 이를 참조하고 있는 현위치 컴포넌트까지 re-render 대상이 된다.
- There is nothing wrong with that, and if rendering of the owning component is fast enough (usually it is!), then this approach works well.
리스트 렌더링에는 전용 컴포넌트를 사용하는 것이 좋다
- 물론 리스트 컴포넌트 중에서, 변경이 있는 컴포넌트만 re-render되는 것은 맞다.
- 하지만 re-rendering 되지 않도록 하면 끝인가? 아니다.
- 조정(reconcile) 프로세스 자체가 비용이 많이 들기 때문. (상세한 내용과 Good practice)
기타
profile에 따라 다른 상수 불러오기
```js
// Common.js
export default {
...require(`../profiles/${process.env.REACT_APP_PROFILES}`)
}
```
```js
// local.js
export const a = 'constant'
```
빌드 시에 profile을 다음과 같이 넣어주면 해당 프로파일.js 파일의 상수들만 불러올 수 있다.
```js
cross-env REACT_APP_PROFILES=local react-scripts build
```
사용할 때는 Common을 import해서 사용.
react에서 POST body는 처리할수 없음.
- react라서 안되는게 아니라 js에서 부터 FE에서 body에 접근하는 인터페이스를 안만들어 두었음.
- https://stackoverflow.com/questions/1409013/how-to-read-the-post-request-parameters-using-javascript
react에서는 DOM element에 사용하는 키워드를 바꿔줘야 함
https://ko.reactjs.org/docs/dom-elements.html
for -> htmlFor / class -> className 으로 변경되는 등.
사례
yobi [공유] 스마트에디터 React, MobX 개선 사례
'JS Stack > JS' 카테고리의 다른 글
[JS] ArrayBuffer와 DataView : TypedArray (0) | 2019.10.31 |
---|---|
[jQuery] checkbox의 check all 기능 구현하기 (0) | 2018.11.30 |
[JS] char <> code <> hex / unicode 공백 / Unpack (0) | 2017.06.04 |
[JS] memoization, currying (0) | 2017.06.02 |
[JS] 함수 #2. Call pattern, 생성자 대안(함수형 패턴), 상속 (0) | 2017.05.31 |