Mobx를 Custom Hooks로 불러오기

Mobx를 Custom Hooks로 불러오기

2023-12-23
수정

spring의 @Bean이나 swift의 @state를 사용해 보고 리액트 상태관리의 일관성에 대해 느꼈습니다. 왜 아직까지 대중적으로 사용되지 않는 걸까요? 여러 상태관리 라이브러리가 있지만, Mobx는 간단한 Flux 구조를 사용하여 Spring의 @Component와 유사한 방식으로 관리할 수 있어서 매력적이었습니다. 그러나 프론트엔드 개발에서는 hooks 기반의 라이브러리들이 생태계에 잘 정착되어 함수형 프로그래밍이 더 편리하게 사용되고 있습니다. 생명주기 관리가 크게 필요하지 않다면 함수형 접근 방식을 권장합니다. 특히 TypeScript와 함께 사용한다면... 그래서 저는 뷰와 상태관리를 분리하는 방법과 가장 함수 친화적으로 Mobx를 TypeScript의 정적 체크 기능과 함께 사용하는 방법을 고민하고 있습니다.

함수형 inject

@inject는 mobx에서 제공하는 스토어에 접근할 수 있는 데코레이터입니다. mobx-react를 사용하면 함수형에서도 사용할 수 있습니다.

mobx-react에서 함수형 inject 사용방법:

type TodoAppComponent = ({ todoStore }: { todoStore: TodoStoreState }) => JSX.Element;

const TodoApp: TodoAppComponent = ({ todoStore }) => {
  const { todos, addTodo } = todoStore;

    {...}
};

export default inject('todoStore')(observer(TodoApp));

todo 페이지에서 todoStore을 가져오는데, props 방식으로 inject 함수를 사용하여 가져옵니다. Next.js와 같은 경우, sspath에서 가져온 prop 등도 받아올 수 있도록 작성하여도 문제가 없습니다.

어떤 다른 하위 컴포넌트에서 위 방식을 사용할 경우:

어떤 다른 하위 컴포넌트에서 위 방식을 사용할 경우

props에서 optonal로 설정하고 타입단언 사용:

type TodoCardProps = {
  {...};
  todoStore?: TodoStoreState;
};

type TodoCardNode = ( todoCardProp: TodoCardProps ) => JSX.Element;

const TodoCard: TodoCardNode ({
  ...,
  todoStore,
}) => {
  const { ... } = todoStore as TodoStoreState;
 {...}
}

export default inject('todoStore')(observer(TodoCard));

자식 컴포넌트에서 일관되게 적용하면 부모 컴포넌트에서 사용할 때 타입 문법에 문제가 발생합니다. 속성이 필요하다는 것을 명시해야 합니다. 그래서 optional로 변경하면 타입 단언도 필요합니다. 스토어를 호출하는 데도 불편함이 생깁니다.

Custom Hooks로 inject

여러 스토어들이 모인 타입:

export interface Store {
  todoStore: TodoStoreState;
  percentStore: PercentStoreState;
  oneStore: OneStoreState;
    {...}
}

useStore:

import { useContext } from 'react';
import { MobXProviderContext } from 'mobx-react';
import { Store } from '@stores/type';

function useStore<K extends keyof Store>(key: K): Store[K] {
  const mobXStore = useContext(MobXProviderContext);
  return mobXStore[key];
}

export default useStore;

useStore을 사용한 하위 컴포넌트:

type TodoCardProps = {
  {...};
};

type TodoCardNode = ( todoCardProp: TodoCardProps ) => JSX.Element;

const TodoCard: TodoCardNode ({
  ...,
}) => {
  const { todos, ... } = useStore('todoStore');
 {...}
}

export default observer(TodoCard);

mobx-react의 컨텍스트를 사용하는 경우, 모든 것을 불러오기 때문에 문장이 길어질 수 있습니다. 따라서, 스토어들의 타입이 모인 스토어 타입을 불러와서 원하는 스토어만 문자열로 받아와 해당 스토어를 반환하도록 구성하였습니다. 이렇게 하면 타입 체크를 모두 사용하여 오류를 방지할 수 있습니다.

참고링크

Mobx 공식문서

KO/EN