Published on

MobX와 React hooks 함께 사용하기

사용 Version

  • mobx: 6.0.4
  • mobx-react: 7.0.5

inject를 대체할 useStores hook

store를 가져오기 위한 helper함수를 만든다.
React.useContext API는 파라미터로 전달된 Context의 현재 값을 반환한다.
useContext와 함께 MobXProviderContext를 사용하면 mobx-react의 Provider가 제공하는 store객체를 가져올 수 있다.

/* /src/stores/useStores.tsx */
import React from 'react';
import { MobXProviderContext } from 'mobx-react';

export function useStores() {
  return React.useContext(MobXProviderContext);
}
/* /src/App.tsx */
import React from 'react';
import './App.css';
import { Provider } from 'mobx-react';
import { LoginStore, UserStore } from './stores';
import UserInfo from './components/userInfo';

const user = new UserStore(['paul', 'mike']);
const login = new LoginStore();

const App = () => {
  return (
    <Provider user={user} login={login}>
      <div>lorem</div>
      <UserInfo />
    </Provider>
  );
};

export default App;

react 컴포넌트에서 store 사용

컴포넌트를 observer로 래핑해준다. 그러면 컴포넌트에서 의존성이 있는 mobx observable의 변화를 감지하고 리렌더링을 할 수 있다.
앞에서 만든 useStores 헬퍼 함수를 사용해서 store객체를 가져온다.

/* /src/components/userInfo.tsx */
import { observer } from 'mobx-react';
import { useStores } from '../stores';

const UserInfo = observer(() => {
  const { user } = useStores();
  const addItem = () => {
    user.addName('added');
  };
  const updateText = () => {
    user.updateText('updated');
  };

  return (
    <div>
      <h2>{user.text}</h2>
      <button onClick={updateText}>update</button>
      {user.names.map((name: string, index: number) => {
        return <p key={`${name} + ${index}`}>{name}</p>;
      })}
      <button onClick={addItem}>add</button>
    </div>
  );
});

export default UserInfo;

MobX Store 구현

makeAutoObservable(this)를 사용해서 해당 클래스를 옵저버블한 상태로 만든다.

/* /src/stores/UserStore.ts */
import { makeAutoObservable } from 'mobx';

export class UserStore {
  names: string[] = [];
  text: string = 'teststr';

  constructor(names: string[]) {
    this.names = names;
    makeAutoObservable(this);
  }

  addName = (name: string) => {
    this.names.push(name);
  };

  updateText = (text: string) => {
    this.text = text;
  };
}