1

I'm trying to create a set of classes that all need to access each other. Following the MobX guide, I would like to have my structure as such:

RootStore
├─ ApplicationStore
├─ UserStore
├─ EventStore
└─ ...Store

Now if I construct each Store with RootStore parameter, I can look up events for user etc. All is good, application works but Jest test explodes when I want to use type hinting:

RootStore.js

import UserStore from './UserStore.mobx'
import ApplicationStore from './ApplicationStore.mobx'

export default class RootStore {
  userStore: UserStore
  appStore: ApplicationStore
}

UserStore.js

import RidersProvider from '../providers/RidersProvider'
import RootStore from './RootStore.mobx'

export default class UserStore {
  provider: RidersProvider
  rootStore: RootStore
  @observable _users = []

  constructor (rootStore: ?RootStore, userProvider: ?RidersProvider) {
    this.rootStore = rootStore
    this.provider = userProvider
  }
  ...

Now if I remove the imports in UserStore, it all works fine, but then I get no type hinting. Is there a good solution to this? I've spent days going through articles on circular references (and losing my mind) but I couldn't find a clue how to properly fix this.

The reference issue I have is as follows: Require cycle: src/Connection.js -> stores/RootStore.singleton.js -> stores/RootStore.mobx.js -> stores/UserStore.mobx.js -> providers/RidersProvider.js -> src/Connection.js

So Connection uses RootStore to access ApplicationStore.accessToken, which is required to get user detail in UserStore. At this point I could just get rid of RootStore which is mentioned in MobX best practices though, unless I misunderstood the concept.

But the problem isn't as much with the RootStore but the fact that if I want to type hint using provider: RidersProvider it fails. In PHP I would have just used a ProviderInterface (and StoreInterface) and never run into a circular dependency but in JS I don't see an alternative other than TypeScript, but is there one?

kachnitel
  • 450
  • 8
  • 20
  • It seems a bad idea to have all classes referencing all others. https://stackoverflow.com/questions/2832017/what-is-the-difference-between-loose-coupling-and-tight-coupling-in-the-object-o – Slim Mar 23 '19 at 07:15
  • Absolutely and if I was working in an actual object oriented language I probably wouldn't have this problem, I see many topics on this issue in Python, but I can't figure out how to achieve loose coupling in JS. I'd love to use interfaces, but... – kachnitel Mar 23 '19 at 07:30
  • Is it really a business need to have all stores referencing each others? Can't you design it in a tree way? – Slim Mar 23 '19 at 07:32
  • That's a topic I haven't covered yet, would [mobx-state-tree](https://github.com/mobxjs/mobx-state-tree/blob/master/docs/getting-started.md#getting-started) be a good place to start? – kachnitel Mar 23 '19 at 08:06
  • Sure, but it's more about you, what do you want to achieve functionnally. Maybe you can draw a diagram listing all possible actions and desired results, and imagine AFTER how to implement it technically, knowing circular references should be avoided. – Slim Mar 23 '19 at 08:27
  • Your code looks like TypeScript, not ES6 or ES7? – Bergi Mar 23 '19 at 12:21
  • What do you mean by "*Jest test explodes when I want to use type hinting*"? Please post the code of the test that is necessary to reproduce this, and the error message that you get. – Bergi Mar 23 '19 at 12:24
  • It might be Stage 1, I thought it's 2, using "guards" rather than statyc typing: [link](https://esdiscuss.org/topic/guards). The test is [here](https://github.com/kachnitel/RideTime/blob/master/stores/__tests__/UserStore.mobx-test.js), it's rather simple and I can see it's an issue with circular dependency if I'm correct, but the error that's thrown is misleading and useless - `TypeError: _RidersProvider.default is not a constructor` though it IS a constructor, works in the app and is even initialized before in the test successfully. (which is a design fault as I don't need to init it in test) – kachnitel Mar 23 '19 at 18:06
  • @Slim That is basically what I did to begin with though, say I want to display `User`'s `Event`s in a list with a title, start time and `Location.name` (Another entity in another store). I'd want `User.get(id)` to give me `{name: Joe, events: Event[]}` rather than calling `EventStore.getEventsForUser(userId)` every time I want to see user detail. Since I was originally asking about Type Hinting, I don't wanna elaborate too much on this implementation here but I'll look into the state tree logic and just try to find a better way to achieve this. – kachnitel Mar 23 '19 at 19:20
  • Sure. have a look on mobx derivation principle. Stores stores raw datas, and constructed data are derivated from stores. Otherwose you can consider your domain completly differently than user-event-location, but design them depending on the requests you will do on it. Again this is just considerations, I don't know mobx. Good cheers! – Slim Mar 23 '19 at 22:43

0 Answers0