ReactMasters / study

스터디 기록
1 stars 0 forks source link

12월 3주차 MobX #37

Open hyeonjoo opened 2 years ago

hyeonjoo commented 2 years ago

MobX

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

State Management Library 중 하나

철학

개념

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