logo
Search검색어를 포함하는 게시물들이 최신순으로 표시됩니다.
    Table of Contents
    [MobX] 1. MobX란?

    이미지 보기

    [MobX] 1. MobX란?

    • 23.01.06 작성

    • 읽는 데 6

    TOC

    가. Mobx의 소개와 특징

    • 상태 관리 라이브러리
    • 단방향 데이터 흐름
    • 데코레이터(@) 지원
    • 객체 지향 느낌이 강하다 ← Redux와 구분되는 특징

    나. MobX의 구성

    1) 상태(state)

    • app을 구동하는 데이터
    • 값을 보유하고 있는 스프레드시트 셀
    • 변경하려는 모든 속성을 MobX가 추적할 수 있도록 observable로 표시
    • 객체의 속성을 스프레드시트 셀로 바꾸는 것과 같다.
    import { makeObservable, observable, action } from "mobx"
    
    class Todo {
        id = Math.random()
        title = ""
        finished = false
    
        constructor(title) {
            makeObservable(this, {
                title: observable,
                finished: observable,
                toggle: action
            })
            this.title = title
        }
    
        toggle() {
            this.finished = !this.finished
        }
    }
    

    2) 동작(action)

    바뀌어야하는 것들(title, finished)은 observable로 표시하는 걸 알겠다. 그런데 toggle의 action은 뭐지?

    • 사용자 이벤트, 백엔드 데이터 푸시, 예약된 이벤트 등과 같이 state를 변경하는 코드 조각
    • 스프레드시트 셀에 새 값을 입력하는 사용자와 같다.
    • 즉, toggle은 observable로 표시된 finished를 변경하는 코드이므로 action으로 표시
    • 다시 말해, action은 state를 변경하는 메서드

    action을 사용하면 뭐가 좋나요?

    • 코드를 구조화하는 데에 도움
    • 의도하지 않은 state 변경 방지

    3) 파생(derivation)

    • 상태(state) 변화에 자동으로 응답
    • 구분
      • computed : 현재의 observable state에서 순수 함수를 사용하여 파생될 수 있는 값
      • reaction : state가 변경될 때 자동으로 발생해야 하는 부수효과

    (official) state 변화로부터 값을 파생하는 경우 되도록 reaction보다는 computed를 활용하는 것이 좋다.

    (사견) React에 대입하면 reactionuseEffect, computeduseMemo와 비슷한 것 같다. 말 그대로 state가 변경될 때 어떤 동작을 시키는 useEffect처럼 react가 작용하고, 단순히 값을 재계산해 캐싱하는 useMemo처럼 computed가 작용하는 것처럼 보인다.


    다. Reactive Programming

    computed와 reaction을 코드로 살펴보자.


    1) 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
        }
    }
    
    • JS의 getter 함수인 get 을 사용하여 속성을 정의하고, makeObservable을 사용해 computed로 표시한다.
    • makeObservable 내부에 observable로 처리한 todos의 변경사항이 있는 경우, computed로 처리한 unfinishedTodoCount가 다시 계산이 되는 구조이다.
    • makeObservbale 내부에서 unfinishedTodoCount는 값으로 취급되지만, 이는 class 내부에서 method를 통해 다른 속성으로부터 값을 계산하는 함수이자, 반환값이다.

    2) side effect

    • state의 변화는 값이나 UI의 변화로 이어진다. 다시 말해 state의 변화의 부수 효과(side effect)를 활용할 수 있어야 하는 것이다.
    • 이 중의 하나는 computed, 또 다른 변화는 reaction이다.
    • reaction은 변화에 반응하는 반응형 프로그래밍, 그리고 그에 따른 추가 동작을 하는 명령형 프로그래밍을 연결하는 요소이다.

    3) reactive component

    import * as React from "react"
    import { render } from "react-dom"
    import { observer } from "mobx-react-lite"
    
    const TodoListView = observer(({ todoList }) => (
        <div>
            <ul>
                {todoList.todos.map(todo => (
                    <TodoView todo={todo} key={todo.id} />
                ))}
            </ul>
            Tasks left: {todoList.unfinishedTodoCount}
        </div>
    ))
    
    const TodoView = observer(({ todo }) => (
        <li>
            <input type="checkbox" checked={todo.finished} onClick={() => todo.toggle()} />
            {todo.title}
        </li>
    ))
    
    const store = new TodoList([new Todo("Get Coffee"), new Todo("Write simpler code")])
    render(<TodoListView todoList={store} />, document.getElementById("root"))
    
    • observer는 리액트 컴포넌트를 data의 derivation으로 변환한다.

    • 필요할 때마다 컴포넌트가 다시 렌더링, 이외에는 렌더링되지 않는다.

    • 위의 예로, TodoListView 컴포넌트는 unfinishedTodoCount가 변경된 경우에만 rerendering한다.

    • 추가로, 위의 예에서 TodoListViewHOC이다.

    • HOC(Higher-Order Components; 고차 컴포넌트)는 컴포넌트를 argument로 받아 또다른 컴포넌트를 반환한다.

    • 위의 예에서는 각 Todo의 템플릿 컴포넌트를 인자로 받아 더 큰 규모의 컴포넌트를 만드는 데에 사용하였다.


    image
    • 데이터는 단방향 흐름을 사용한다.
    • 즉, action이 state를 변경하는 단방향 흐름을 만들고, 이에 영향을 받는 모든 view를 업데이트한다.
    profile

    FE Developer 박승훈

    노력하는 자는 즐기는 자를 이길 수 없다