몽땅뚝딱 개발자

MobX 사용하기 본문

Development/React.js · Next.js

MobX 사용하기

레오나르도 다빈츠 2025. 2. 23. 15:48

 

 

주요 특징

1. 반응형 프로그래밍: MobX는 상태가 변경되면 해당 상태를 참조하는 모든 컴포넌트가 자동으로 다시 렌더링된다.

2. 간단한 문법: Observable state(관찰 가능한 상태), Actions(상태 변경 로직), Computed values(파생 상태)를 사용하여 상태 관리가 직관적이고 간단하다.

3. 유연한 구조: 리덕스처럼 강한 규칙이나 보일러플레이트가 필요없어서 구조와 패턴을 비교적 자유롭게 설계할 수 있다.

4. 높은 성능: 필요한 부분만 리렌더링하기 때문에 React와 함께 사용할 때 성능이 우수하다.

 

 

 

사용하기

함수형, 클래스형 둘 다 작성할 수 있는데 함수형으로 사용하는 경우 함수형 컴포넌트에 observer를 붙여야햔다.

 

📄 작성하기

- makeAutoObservable: 모든 클래스 속성을 자동으로 observable, 메서드는 action으로 설정한다. 여기서 더 세밀하게 설정하고 싶은 경우, 예외적인 경우(얕은 비교, 깊은 비교, 비교하지 않음 등등)에만 값을 추가하면 되므로 상대적으로 관리할 코드가 적다.

- makeObservable: 기본값이 자동으로 설정되지 않는다는 점이 makeAutoObservable과 다르다. 더 세밀하게 설정하고 싶을 때 사용한다.

- @observable 데코데이터 사용: React Native에서 사용하기가 힘들어 지양한다.

class CounterStore {
  count = 0;

  // 예시 1. makeAutoObservable()을 사용하는 경우
  constructor() {
    makeAutoObservable(this, {
    	count: false
    });
  }
  
  // 예시 2. makeObservable()을 사용하는 경우
  constructor() {
    makeObservable(this, {
    	count: observable
    });
  }

  increment() {
    this.count++;
  }

  decrement() {
    this.count--;
  }
}

 

📄 컴포넌트

import React from "react";
import { observer } from "mobx-react-lite";
import { useLocalObservable } from "mobx-react-lite";

const Counter = observer(() => {
  // ...
});

export default Counter;

 

 

 

사용가능한 옵션들

- observable: 기본값. 깊은 추적을 한다.

- observable.ref: 최적화 용도로 참조 자체만 추적하여 객체 내부 변경은 무시한다.

- observable.shallow: 최적화 용도로 1단계 깊이만 추적한다.

- observable.struct: 최적화 용도로 깊은 비교 후 변경 시에만 리렌더링한다.

- action: 상태를 변경하는 동기 메서드

- action.bound: this를 클래스 인스턴스에 바인딩한다.

- computed: 의존성에 따라 계산 및 캐싱

- flow: 비동기 작업 (generator function과 함께 사용)

- false: 상태 추적 제외 (반응형 시스템에서 제외)

 

 

 

flow 사용하기

MobX는 await 구문 뒤를 추적하지 않는다. 비동기 작업(await) 이후의 상태 변경은 메인 스레드가 아닌 콜백 큐에서 나중에 실행된다. MobX는 동기적으로 실행된 코드 블록만 추적하기때문에 이 부분을 하나의 연속된 코드 블록으로 인식하지 않는다. 따라서 상태 변경을 추적하지 않고 UI도 업데이트 되지 않는 것이다.

 

💡 자바스크립트

자바스크립트는 싱글스레드 언어로 비동기 처리를 위해 이벤트 루프와 콜백 큐를 사용한다. await는 비동기 작업이 완료될 때까지 기다렸다가 다음 줄의 코드를 콜백 큐에 넣고 나중에 실행한다.

 

class Store {
  count = 0;
  isLoading = false;

  constructor() {
    makeAutoObservable(this);
  }

  async incrementAsync() {
    this.isLoading = true;   // ✅ 추적 O
    await new Promise((resolve) => setTimeout(resolve, 1000));
    this.count++;            // ❌ 추적 X
    this.isLoading = false;  // ❌ 추적 X, isLoading 변수를 사용하는 UI는 업데이트되지 않는다.
  }
}

 

 

 

 

해결방법은 두가지로, flow와 runInAction을 사용하는 것이다.

 

📄 flow 사용하기

제너레이터 함수(function*)와 yield를 사용한다. async, await 대신 yield를 사용하여 비동기 작업을 중단하고 상태를 추적한다. 비동기 작업 중에도 상태를 추적하고 MobX의 반응형 시스템 안에서 상태 변경을 관리한다. 

class Store {
  count = 0;
  isLoading = false;

  constructor() {
    makeAutoObservable(this);
  }

  *incrementAsync() {
    this.isLoading = true;   // ✅ 추적 O
    yield new Promise((resolve) => setTimeout(resolve, 1000));
    this.count++;            // ✅ 추적 O
    this.isLoading = false;  // ✅ 추적 O
  }
}

 

 

📄 runInAction 사용하기

await 뒤에 상태 변경을 동기 코드 블록으로 감싼다. runInAction은 동기적으로 상태 변경을 묶어 MobX가 추적할 수 있게 만든다. runInAction 내부의 상태 변경은 동기 코드 블록으로 인식되어 MobX가 상태 변화를 추적하고 UI가 리렌더링 될 수 있도록 한다.

async incrementAsync() {
  this.isLoading = true;
  await new Promise((resolve) => setTimeout(resolve, 1000));
  
  runInAction(() => {
    this.count++;
    this.isLoading = false;
  });
}

 

'Development > React.js · Next.js' 카테고리의 다른 글

[React] Provider, useContext  (0) 2024.08.03
[Next.js] 스토리북 도입 (미작성)  (0) 2023.12.29
[Next.js] 스타일링 도구  (0) 2023.12.20
[Next.js] 기본 개념  (0) 2023.12.20
React Query 개념 정리  (1) 2023.10.19
Comments