class 형식으로 Mobx 사용해보기

dante Yoon·2020년 4월 9일
4

mobx

목록 보기
1/1
post-thumbnail

👉 Mobx?

리엑트에서 state 관리를 위한 전략은 여러가지입니다.
가장 널리 알려진 redux,
useState hooks를 이용한 각 컴포넌트 레벨에서의 관리,
contextAPI 를 이용한 컴포넌트들 간의 state 관리,
그리고 mobx를 이용한 관리 등등.

저는 redux, redux-saga를 이용해 api call에 대한 side effect를 관리해 본 경험이 있는데요,
최근에는 mobx를 사용하며 redux보다 보다 편리하고 빠르게 state 관리를 하고 있습니다.

👉 How Mobx?

Mobx를 사용하는데 있어서 크게 두 가지로 나뉘어 볼 수 있을 것 같습니다.
1. 클래스형식의 state 관리,
2. useLocalStore, 즉 hooks를 이용한 관리

오늘은 클래스 형식의 관리를 다뤄보려고 합니다.

본 포스팅은 아래의 docs를 참고했습니다.

  1. mobx-react
  2. mobx

필요한 사항

mobx-react-lite, mobx, lorem picsum api

	yarn add mobx mobx-react-lite
    
    lorem picsum api는 아래 사이트에서 확인하실 수 있습니다.

https://picsum.photos/

👉 루트스토어 작성해보기

//store/rootstore.ts

import { observable } from 'mobx';

class RootStore {
  @observable authToken: string = '';

export default RootStore; 

본 예제에서 jwt 토큰 구현과 같은 유저 인증은 다루지 않습니다.
루트 스토어는 말 그대로 여러 store를 포함하고 접근할 수 있는 스토어의 모체입니다.
예를 들어 picture store, shopping store와 같은 여러 store가 존재한다고 생각해보면 이러한 서브 스토어들은 루트 스토어를 extends 해야 합니다.

lorem picsum api는 더미 사진 데이터를 response로 보내줍니다. 이 데이터들을 state 안에서 관리할 수 있게 하는 picList store를 만들어보겠습니다.

👉 서브스토어 작성해보기

//rootstore/picList.ts
import RootStore from 'store/rootstore'; 

export type PictureList = {
	id: string;
	author: string;
	height: number;
	url: string;
	download_url: string;
}

class PicListStore extends RootStore {
  @observable picList: PictureList[] // 받을 더미데이터 리스트
  @observable page: number;//요청할 데이터의 페이지 
  @Observable limit: number;//한 페이지에 받을 더미데이터 개수 
  constructor(rootStore: RootStore) {
    super();
    this.rootStore = rootStore;
  }

  @action.bound
  async fetchImages() {
    try{
      this.onRequest(); 
      const [, ListResponse ] = await requestList({page: this.page, limit: 10});  
      ListResponse ? this.pictureList = [...this.pictureList, ...ListResponse] : '';
      this.page++; 			
    }catch(error){
      this.onFailure(error);
    }
    this.onSuccess(); 
  }

}

export default PicListStore; 

한번살펴볼까요? 위의 데코레이터 사용을 위해서는 tsconfig.ts와 .babelrc에 추가 설정을 해줘야 합니다. 해당 설정에 대한 설명은 아래 포스팅을 참조해주세요!
jay의 next.js config 설정방법

observable 데코레이터는 앱 구동환경에서 변경되며 관리할 state에 대해 표시를 해줍니다.
action 데코레이터를 통해 해당 함수에서 state가 변경되는 것을 말해줄 수 있습니다.

꼭 데코레이터를 사용하지 않아도 됩니다 :) 데코레이터를 처음 접하시는 분은 해당 표현에 너무 부담을 갖지 마시고 공식 문서를 한번 읽어보시는게 도움이 되실 거라고 생각합니다.

위와 같이 만든 클래스를 한번 함수형 컴포넌트에서 사용해볼까요?

👉 Store 호출 훅 작성해보기!

//store/index.tsx 
import {useLocalStore} from 'mobx-react-lite';
import React, {FC, createContext, useContext } from 'react';
import PicListStore from './picList'; 
export type RootStoreType = {
	picList: PicListStore
}
// key 형식으로 원하는 스토어를 선택해서 사용할 수 있습니다. 
export type StoreKeys = keyof RootStore; 
//어느 컴포넌트에서도 스토어를 호출해 사용할 수 있도록 contextAPI를 사용할 것입니다. 
const storeContext = createContext<RootStore | null>(null);

// 앱에 RootStore가 존재하지 않는다면 초기화시켜줍니다. 
const initRootStore = (): RootStore => {
	const rootStore: RootStore = {} as RootStore;
	rootStore.picList = new PictureListStore(rootStore); 
	return rootStore;
}

//contextAPI Provider 
export const StoreProvider: FC = ({ children }) => {
  const store = useLocalStore(initRootStore);

  return <storeContext.Provider value={store}>{children}</storeContext.Provider>
}

//
export function useStore<K extends StoreKeys>(storeName: K): RootStore[K]{
  const store = useContext(storeContext); 
  if(!store) throw new Error('해당 useStore 훅은 StoreProvider 안에서 사용되어야 합니다! '); 

  return store[storeName]; 
}

위 storeProvider FC에 useLocalStore를 사용했습니다.
useLocalStore는 훅에서 mobx를 사용할 수 있게 해주며
contextAPI와 함께 어느 함수 컴포넌트에서라도 내가 필요한 스토어를 사용할 수 있습니다.

👉 훅을 이용해 내가 만든 스토어 호출하기 !

위에서 만든 store class를 호출해서 사용해보세요.

import React, {FC} from 'react';
import {useStore} from 'store';

const UseStoreExample: FC = () => {
  const getPictureList = useStore("picList");
  const { fetchImages, pictureList} = getPictureList; 
  return(
    <>
    	...
    </> 
  )
}

👉 여기까지 오시느라 수고 많았습니다 !

멋지네요.
앞서 PicListStore 에서 만들었던 fetchImages 함수와 pictureList state를 앱 전체 내에서 자유롭게 불러서 사용할 수 있게 되었습니다.

공유는 꼭 출처를 남겨주세요

profile
성장을 향한 작은 몸부림의 흔적들

1개의 댓글

comment-user-thumbnail
2020년 6월 23일

감사합니다.

답글 달기