Integration with RootStore
This recipe may be helpful if you need access to your RootStore inside your ViewModel implementations.
Follow the steps:
- Make a base
ViewModelimplementation that acceptsRootStoreas a constructor parameter.
ts
// view-model.impl.ts
import { ViewModelBase, type ViewModelParams } from 'mobx-view-model';
import type { RootStore } from '@/shared/store';
export class ViewModelImpl extends ViewModelBase {
constructor(
protected rootStore: RootStore,
params: ViewModelParams,
) {
super(params);
}
// example of your custom methods
// and properties
get queryParams() {
return this.rootStore.router.queryParams.data;
}
}- Configure a
ViewModelStorefactory that passesRootStoreto classes derived from that base implementation. Using the factory instead of overridingcreatepreserves the store'svmConfigmerging and per-creationfactoryoverrides.
ts
// view-model.store.impl.ts
import { ViewModelStoreBase, viewModelsConfig } from 'mobx-view-model';
import { ViewModelImpl } from './view-model.impl';
import type { RootStore } from '@/shared/store';
export class ViewModelStoreImpl extends ViewModelStoreBase {
constructor(protected rootStore: RootStore) {
super({
vmConfig: {
factory: (params) => {
const VM = params.VM;
if (VM === ViewModelImpl || VM.prototype instanceof ViewModelImpl) {
return new VM(rootStore, params);
}
return viewModelsConfig.factory(params);
},
},
});
}
}An explicit factory in a creation config takes precedence; a per-view-model vmConfig.factory can also override this store default.
- Add
ViewModelStoreinto yourRootStore
ts
import type { ViewModelStore } from 'mobx-view-model';
import { ViewModelStoreImpl } from '@/shared/lib/mobx';
export class RootStoreImpl implements RootStore {
viewModels: ViewModelStore;
constructor() {
this.viewModels = new ViewModelStoreImpl(this);
}
}- Create a
Viewwith aViewModel
tsx
import { observable } from 'mobx';
import { withViewModel } from 'mobx-view-model-react';
import { ViewModelImpl } from '@/shared/lib/mobx';
export class MyPageVM extends ViewModelImpl {
@observable
accessor state = '';
protected async willMount() {
await this.rootStore.beerApi.takeBeer();
}
protected didMount() {
console.info('did mount');
}
}
export const MyPage = withViewModel(MyPageVM, ({ model }) => {
return <div>{model.state}</div>;
});View must not be wrapped
withViewModel wraps the View in observer itself. Pass a plain render function; wrapping it in observer or React.memo first causes Error #4.
