티스토리 뷰

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

저번 글에 이은 2탄입니다. MobX에는 Redux와는 다르게, 복수의 Store가 존재하며, 복수의 Provider를 보유할 수 있습니다.  Redux에도 Provider가 있지만, 그것은 컴포넌트의 루트에 한개만 존재하고, 초기 설정만 끝마치면 평소에는 의식할 일이 없는 존재입니다.


MobX에서, Store를 어디에서 생성하고 어떻게 Provider를 전달하는게 좋은 설계일까요.  이 관점에 대해 깊이 고찰한 글을 찾을 수 없었기 때문에, 독자방침이지만 끄적여보도록 하겠습니다 (친절한 태클을 기다려봅니다. )

Redux 답습 패턴

Redux 구현 경험자도, 또 경험이 없는 분도 이 방법이 가장 이해하기 쉽다고 생각합니다.  'Provider를 한개만 갖도록 한다' 입니다.  이렇게 하면 모든 컴포넌트가 전체의 상태를 액세스 할수 있도록 되며, Redux의 1Store와 같은 선상에서 생각할 수 있게 됩니다. 심플한것을 추구한다면 이것으로 충분하겠죠.

routes.js
import StoreA from 'stores/storeA'
import StoreB from 'stores/storeB'
import StoreC from 'stores/storeC'
const stores = {
  storeA: new StoreA(),
  storeB: new StoreB(),
  storeC: new StoreC()
}

export const Routes = () => {
  return (
    <Provider { ...stores }>
      <Router history={ history }>
        <Route path="/A" component={ ComponentA } />
        <Route path="/B" component={ ComponentB } />
        <Route path="/C" component={ ComponentC } />
      </Router>
    </Provider>
  )
}


하지만 한 번더 생각해 보세요.  Store가 엄청난 수로 불어나게 될 것을 상상해보세요.

'몇십개의 Store가 생겼을때 어플리케이션을 초기화하려면 new Store 하게 되는데 그걸로 괜찮아? 필요없는 Store를 확보하고 있지는 않나?' 라고 하는 것입니다. 

당신의 SPA、메모리 사용이 심하지 않습니까?

SPA로 무언가 상태관리를 구현한 경험이 있는 분은 어느 시점에서 눈치챌거라 생각합니다.  Store의 상태는 방치해두면,  너무 거대해진다는 것을..  화면에 표시하는 와중에 불필요해진 상태를 해제시키는 처리를 어딘가에 구현해 두어야 합니다.  혹시 이 관점을 의식하지 않으면 비 SPA에서는 직면하지 않았던 문제가 나타나는 것도 시간문제입니다. 

Redux의 경우, container가 그 해방역활을 담당하게 됩니다.  화면 표시에 필요없어진 정보는 unMount할때 보통 해제합니다.  물론 어떤 조건에서 해제 할지는 설계에 따라 다르겠죠.

MobX에서는 Container가 존재하지 않기 때문에 위의 기능을 대신하는 층이 필요하게 됩니다.  거기서 'react-router/Route' 'mobx-react/Provider' 'Store' 를 밀접하게 결합시키는 패턴이 이하의 Route 결합패턴 입니다. 

Route 밀접 결합 패턴

MobX에 구현하게 되면, src 디렉토리에서 components, stores, 라고 하는 파일군이 반드시 생길거라고 생각합니다.   필자는 거기에 더해서 providers 디렉토리를 확보해서 Provider로 래핑된 Route용 컴포넌트를 정의합니다.

routes.js
import rootStore from 'stores/root'
import ProviderA form 'providers/providerA'
import ProviderB form 'providers/providerB'
import ProviderC form 'providers/providerC'

export const Routes = () => {
  return (
    <Provider rootStore={ rootStore }>
      <Router history={ history }>
        <Route path="/A" component={ ProviderA } />
        <Route path="/B" component={ ProviderB } />
        <Route path="/C" component={ ProviderC } />
      </Router>
    </Provider>
  )
}

providerA.js

import { Component } from 'react' import { Provider } from 'mobx-react' import StoreA from '~/stores/storeA' import ComponentA from '~/components/componentA' export default class ProviderA extends Component { componentWillMount() { this.store = new StoreA() } componentWillUnmount() { this.store = void 0 // Unmount 할때 해제 } render() { return ( <Provider storeA={ this.store }> <ComponentA /> </Provider> ) } }

꽤나 조악한 예일지도 모르겠지만, routing을 다루는데 필요한 store를 필요한 만큼 생성하는 것이 가능해집니다.  해제수단은 여러가지 설계가 가능합니다. 

  • 마운트 할때마다 API를 부르고 싶지 않다.
  • 언마운트 할때 일부 상태만 해제하고 싶다. 
  • 열람환경의 퍼포먼스를 검증한 후에 해제하고 싶다. 

이런 요건에 대응 가능한 Providers층을 새롭게 갖게 되는 것으로, 후에 메모리 압박 위험을 회피할수 있습니다.   또한 MVC프레임워크의 컨트롤러와 같은 역할을 할 수 있을 것으로 보입니다. 

다만, 모든 컴포넌트에 모든 Store의 접근이 가능한 구조가 아니게 됩니다.  컴포넌트가 있는 Store를 참조 하는 때에는, 거기에 연결된 Provider에 내포되어 있는 것이 요건입니다.  '아아..  이쪽 컴포넌트에서도 저쪽의 Store에 있는 상태를 공유하고 싶다..'  라고 생각이 들때는, 상위 층의 ProviderStore를 migrate 합시다.  해제, 유지등의 의뢰는 해당 Provider에 참조하고싶은 Store를 inject하여 action을 dispatch하면 될것으로 보입니다.

providerA.js
import { Component } from 'react'
import { Provider }  from 'mobx-react'
import StoreA        from '~/stores/storeA'
import ComponentA    from '~/components/componentA'

@inject(s => ({
  retainAction:  s.upperStore.someRetainAction
  disposeAction: s.upperStore.someDisposeAction
}))
export default class ArticlesProvider extends Component {
  componentWillMount() {
    this.props.retainAction()
  }
  componentWillUnmount() {
    this.props.disposeAction()
  }
  render() {
    return (
      <Provider articleStore={ this.store }>
        <ComponentA />
      </Provider>
    )
  }
}

원본 : https://qiita.com/Takepepe/items/59d1396c25c8a699c41c

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함