Posts [학습할래] Mobx
Post
Cancel

[학습할래] Mobx

1) Mobx 란?

mobx는 프론트엔드에서 사용하는 애플리케이션 상태 관리 프레임워크입니다. 애플리케이션 전반에서 사용하는 상태(state, 자주 변경되어 관리되는 데이터)를 손쉽게 관리하여 변경에 대한 반응을 처리해줄 수 있는 라이브러리입니다. 보통 리액트에선 Redux와 Mobx를 많이 사용하며 INHR+는 Mobx를 사용하고 있습니다.

2) 상태란 무엇일까?

image-20220407-101614

예를 들어, 현재 개발하고 있는 CMS 구성원 상세 팝업에서 대표 조직 토글 버튼을 클릭시 화면에서 자동으로 on/off 처리가 됩니다. 이처럼 사용자의 인터렉션을 통해 자주 변경되어 관리되어야 하는 데이터를 상태(state)라고 합니다.

3) mobx와 같은 상태 관리 프레임워크를 사용하는 이유는…??

리액트는 기본적으로 UI 요소(컴포넌트)를 지우고 다시 그린다는 철학을 가지고 있습니다. 예를 들어, 아래 이미지와 같은 Input 필드에 유저가 타이핑을 하면 dom 트리 내부적으로 지우고 다시 그리게 됩니다.

image-20220407-102006

이라고 입력되어 있는 상태에서 전1 을 입력하는 순간 dom 트리내부에서 전1 이라고 입력되어 있는 Input 필드를 다시 그리게 되는 것입니다. 그리고 부모 컴포넌트가 렌더링될때 자동으로 자식 컴포넌트도 렌더링되게 됩니다.

이를 컴포넌트 구조로 임의로 가정해서 도식화해보겠습니다.

image-20220407-102126

위 이미지와 같이 name 이란 상태를 가지고 있는 Container 부모 컴포넌트가 있고 자식 컴포넌트에 Component1, Component2 가 있다고 가정했을때 name 상태를 변경했을때 불필요한 Component2의 렌더링도 일어나게 됩니다. 이는 성능에 안 좋은 영향을 미치며 애플리케이션 구조가 커질수록 data-flow가 복잡해져 버그나 오류에 대한 트래킹이 어려워지게 됩니다.

그래서 정리하자면 아래 두 가지와 같습니다.

  • 1)상태 관리를 쉬워지도록 하여 상태 로직을 분리하여 모듈화할 수 있다.
  • 2)상태 관리의 단계를 간결하게 해준다.(렌더링 성능 개선에도 좋은 영향을 끼친다)

4) mobx의 주요 요소

State(Observable State): 관찰 받고 있는 상태

  • 실제로 mobx과 상태로 관리하고 있는 object
  • 이 state의 변화는 reaction과 computations를 일으킴
  • mobx6의 observable에 해당함

Derivation(Computed values) - 파생 값(연산된 값)

  • Observable State의 변화에 따라 연산되어 나오는 값
  • 특정값을 연산할 때에만 처리됨
  • observable로부터 도출할 수 있으며, 값이 변경되면 자동으로 업데이트
  • 성능 최적화를 위해 사용함
  • 메모리에 연산된 값을 캐슁하여, 만약 state가 변경되지 않을 경우 다시 연산하지 않고 캐슁되어 있는 값을 그대로 사용함
  • mobx6의 computed 에 해당함

Reactions - 반응

  • Observable State의 변화에 따른 부가적인 변화
  • 값이 바뀜에 따라 해야 할 일을 정하는 것을 의미
  • 적당할 때 자동으로 DOM이 업데이트 되거나 네트워크 요청을 하도록 만듬
  • when, autorun, reaction
  • 리액트 컴포넌트에 observer 함수로 감싸면 mobx에 내부적으로 컴포넌트 렌더링 메소드를 autorun으로 감싸서 상태 변화에 재렌더링을 하게 함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
interface Props {

}

const App: React.FC<Props> = observer((props) => {
    const person = new Person("jeon young ho");

    const { countClass, countObject, doubleClassAuto } = store;

    autorun(() => {
      if (doubleClassAuto.double) {
        console.log('Double' + doubleClassAuto.double)
      }
      if (doubleClassAuto.double === 8) {
        console.log('만약 value가 8이라면 0으로 초기화')
        doubleClassAuto.value = 0
      }
    })
    console.log("render! " + s.text);

    return (
        <div style=>
            <div className={s.text}>person name: {person.name}</div>
            <div style=>
                <h1>Count(Class)</h1>
                <div>number: {countClass.number}</div>
                <button onClick={() => countClass.increase()}>plus</button>
                <button onClick={() => countClass.decrease()}>minus</button>
            </div>
        </div>
    );
});
export default App;

Actions : 액션, 상태를 변화시키는 것

  • Observable State가 사용자가 지정한 것을 포함한 모든 변경사항
  • 상태를 변경시키는 모든 것
  • MobX는 모든 사용자의 액션으로 발생하는 상태 변화들이 전부 자동으로 파생값(Derivation)리액션(Reactions)으로 처리되도록 함
  • mobx6의 action 에 해당함

Note: 실제로 상태를 변경하는 함수에 action을 변경하지 않아도 자동적으로 reaction이 일어난다. 그렇다면 왜 action이 존재할까? 바로 action이 상태 변경을 트랜잭션 처리하기 때문이다. 예를 들어, foo() 라는 함수에서 observable 변수 a = 1, b = 2 로 변경하였다. 만약 action으로 지정된 함수라면 이를 하나의 변경으로 처리하여 한 번에 반영시키고, action이 지정되지 않은 함수라면 각각 하나씩 변경을 감지하여 두 번을 렌더링시키게 된다. 이는 성능적인 측면에서 action을 붙여주는게 좋다.

5) mobx의 동작 흐름

161419401-8b780f9c-f519-4ded-932a-61ba397b718c-20220407-103032

위의 이미지는 mobx api 의 생명 주기를 요약해서 나타내고 있습니다. Action으로 인한 상태(State) 변경은 곧, 계산 결과(computed)를 업데이트합니다. 계산 결과가 업데이트 되면 곧 이를 구독하는 반응(Reaction)을 일으키게 됩니다. 그럼으로써 컴포넌트가 자연스레 리렌더링 되게 됩니다.

6) 이해하기 쉬운 INHR+ 를 통한 예제

INHR+ 프론트엔드는 MVVM 아키텍처를 가지고 있습니다.

  • view: 뷰의 역할은 UI 를 구성하는 역할을 담당한다. 사용자가 스크린을 통해 보는 구조, 레이아웃, 형태를 형태를 정의한다. 일반적으로 화면에서 보여지는 presentation 영역이라 볼 수 있고, 비즈니스로 로직을 포함하지 않는다.

  • view-model: view가 사용할 메서드와 필드를 구현하고, 뷰에게 상태 변화를 알리는 것이다. view는 view-model의 상태 변화를 observing 한다. 일반적으로 view-model 은 모델의 데이터를 가공해서 뷰에 전달하는 역할을 담당한다고 쉽게 생각할 수 있다.

  • model: INHR+ 에서는 이 부분을 service라 칭한다. 비즈니스 로직과 유효성 검사 및 실제 상태(state)를 가지는 데이터를 관리한다. 실제 api 호출이 일어나는 부분도 model 에서 주로 일어나게 된다.

MVVM 아키텍처와 관련된 더 자세한 내용은 여기 를 참고하자.

구성원 상세에서 병역사항 ‘군별 및 계급’ 필드를 예로 들어보겠습니다.

image-20220407-121114

  • model(service): MilitaryFormService.ts
  • view-model: MilitaryDivisionRankEditFieldVM.ts
  • view: MilitaryDivisionRankEditField.tsx

만약, 위와 같은 상황에서 군별을 공군 으로 바꿀 경우 어떤 과정이 일어나서 화면이 렌더링될까요?

image-20220407-121252

  • 1)유저가 드롭다운을 클릭하여 공군 을 선택한다. (Event)
  • 2)model에서 상태(state, 군별) 변경이 일어난다. (Actions)
  • 3)view-model의 파생 값(Computed values), 즉 연산된 값의 변경이 일어난다. (Derived)
  • 4)view에 속하는 해당 컴포넌트가 렌더링된다.(Reactions)

즉 위에서 언급했던 mobx api 라이프사이클에 의해 화면이 렌더링된 것을 확인할 수 있습니다.

7) Mobx api 사용법

mobx는 버전 별로 사용법이 다릅니다. 기존 inhr 에서 사용된 4버전은 데코레이터(spring의 annotation과 동일한 모습, @observable)를 사용하고, 6버전은 makeObservable, makeAutoObservable 를 사용합니다.

더 자세한 mobx api 사용법은 제 블로그 및 공식 레퍼런스를 참고하시면 됩니다!

8) 마치며

지금까지 mobx 에 대해 알아보는 시간을 가져보았습니다. 리액트를 모르는 상태에서도 이해하기 쉽도록 신경 썼는데 이해가 좀 되셨을지 모르겠네요ㅎㅎ 학습할래? 를 준비하면서 뭔가 사용하고 있는 기술들을 한 번 더 스스로 정리해볼 수 있는 기회가 되서 저에게도 정말 유익한 시간이었고 다음에는 더 유익한 주제로 준비해보겠습니다!!! 감사합니다 :)

This post is licensed under CC BY 4.0 by the author.