Skip to content

12월 3주차 MobX #37

@hyeonjoo

Description

@hyeonjoo

MobX

Created: December 18, 2021 1:53 PM
Tags: frontend

State Management Library 중 하나

철학

  • 쉽다.
  • UI framework 밖에서 상태 관리가 가능하다.
    • Redux는 React 없이 .. 돌아간다.
  • 렌더링 최적화를 쉽게 할 수 있다
    • 데이터 모든 변경, 사용을 런타임에 추적
    • 상태와 출력 사이 모든 관계를 나타내는 dependency tree를 만들어서, 리액트 컴포넌트처럼 필요한 경우에만 상태에 따라 연산 실행
    • Memoization, selector 등을 사용하는 컴포넌트 최적화 작업은 할 필요가 없다.

개념

  1. 상태(state)

  2. 동작(action)

  3. 전파(derivation)

  4. 상태(state)를 정의하고 observable로 표시해주기

    State 담기는 데이터 구조는 아무거나 상관 없다. 객체, 배열, 클래스 등...

    대신 MobX가 추적할 수 있도록 observable 로 표시해줘야 한다.

  5. action 을 이용해서 state 를 업데이트하기

  6. state 변경에 자동으로 응답하는 derivation 만들기

    • computed 값: 남은 Todo 개수 같이 순수 함수를 사용해서 파생되는 값.

    • reaction: 서버에 변경 사항 전송하기 같이 state 변경되면 자동으로 발생되어야 하는 side effect. 그치만 과하게 사용될 수가 있으니 가능한 computed 쓰기.

    • computed 쓰는 예시

      import { makeObservable, observable, computed } from "mobx"
      
      class TodoList {
          todos = []
          get unfinishedTodoCount() {
              return this.todos.filter(todo => !todo.finished).length
          }
          constructor(todos) {
              makeObservable(this, {
                  todos: observable,
                  unfinishedTodoCount: computed
              })
              this.todos = todos
          }
      }

동작 요약

Uni-directional data flow

Untitled

import React from "react"
import ReactDOM from "react-dom"
import { makeAutoObservable } from "mobx"
import { observer } from "mobx-react"

**// State model**
class Timer {
    secondsPassed = 0

    constructor() {
        makeAutoObservable(this)
				//  makeObservable(this, {
				//		secondsPassed: observable,
				//		increase: action,
				//		reset: action
				//  }
    }

    increase() {
        this.secondsPassed += 1
    }

    reset() {
        this.secondsPassed = 0
    }
}

**// Create the state class instance**
const myTimer = new Timer()

**// Component using the observable state (timer)**
const TimerView = observer(({ timer }) => (
    <button onClick={() => timer.reset()}>Seconds passed: {timer.secondsPassed}</button>
))

ReactDOM.render(<TimerView timer={myTimer} />, document.body)

setInterval(() => {
    myTimer.increase()
}, 1000)
  1. event: onClick , setInterval
  2. action: myTimer.increate , myTimer.reset
  3. update: action 들이 observable state 업데이트
  4. side-effects: 업데이트가 인지되어 렌더링 실행됨 → TimerView 컴포넌트는 timer.secondsPassed에 의존해서 렌더링

참고

  1. React 컴포넌트를 감싸는 observer 함수는 HOC(Higher-Order Components)함수. 컴포넌트를 감싸서 반응형으로 만들어준다. 렌더링 중에 사용되는 모든 observable에 React 컴포넌트들을 자동으로 구독한다.

  2. autorun 을 사용해서 state가 변경될 때마다 로그를 출력할 수 있다.

  3. mobx-react-lite 패키지는 이름처럼 더 가볍고 함수형 컴포넌트만 지원한다. useContext 를 이용해서 state 를 컴포넌트에 연결한다.

  4. observer 컴포넌트에서 외부 state 사용하려면

    1. props 사용하기: state 인스턴스를 prop으로 넘기기

    2. 전역 변수 사용하기 (비추)

    3. React context 사용하기

      import {observer} from 'mobx-react-lite'
      import {createContext, useContext} from "react"
      
      const TimerContext = createContext<Timer>()
      
      const TimerView = observer(() => {
          // 컨텍스트에서 타이머를 가져옵니다.
          const timer = useContext(TimerContext) // 위의 타이머 정의를 참고하세요.
          return (
              <span>Seconds passed: {timer.secondsPassed}</span>
          )
      })
      
      ReactDOM.render(
          <TimerContext.Provider value={new Timer()}>
              <TimerView />
          </TimerContext.Provider>,
          document.body
      )
  5. 리액트 컴포넌트는 최소화하기

    observer 컴포넌트들은 모든 값을 추적하고 변경사항이 있으면 다시 렌더링하기 때문에 작을수록 다시 렌더링해야 하는 변경사항이 적다!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions