ViewModelsConfig
configuration object
This configration contains all options for some behaviour of ViewModel
instances.
The package provides a global object with this configuration, but you can also change it for each ViewModel
and ViewModelStore
separately using the vmConfig
field.
import {
viewModelsConfig,
withViewModel,
ViewModelStoreBase
} from "mobx-view-model";
viewModelsConfig.comparePayload = false;
import { withViewModel } from "mobx-view-model";
viewViewModel(VM, {
vmConfig: {
comparePayload: false
}
})()
new ViewModelStoreBase({
vmConfig: {
comparePayload: false
}
})
Recommendations
These are the recommended settings for the global configuration viewModelsConfig
, which contain the most optimal values.
import { loadableDefaultConfig } from '@one-web/uikit-7';
import { viewModelsConfig, ViewModelStoreBase } from 'mobx-view-model';
viewModelsConfig.comparePayload = false;
viewModelsConfig.payloadComputed = 'struct';
viewModelsConfig.payloadObservable = 'ref';
viewModelsConfig.wrapViewsInObserver = true;
viewModelsConfig.observable.viewModels.useDecorators = true; //false
viewModelsConfig.observable.viewModelStores.useDecorators = true; // false
startViewTransitions
Indicates whether to enable transitions for the start view.
MDN Reference
WARNING
This feature is experimental and not all browsers support it yet.
comparePayload
Allows you to configure how payload should be compared
'strict'
- (default) strict equality (comparer.structural
from MobX)'shallow'
- shallow equalityfalse
- (recommended) no comparisonfn
- custom payload compare fn (e.g. MobX comparer functions)
payloadComputed
Allows you to configure computed
statement of the payload
'struct'
- (recommended)computed.struct
from MobXtrue
-computed
from MobXfn
- custom equality function forcomputed
from MobXfalse
- (default) do not wrappayload
intocomputed
MobX utility
payloadObservable
Indicates type of observable for ViewModel
payload.
'ref'
- (default) (recommended) MobX ref observable'deep'
- MobX deep observable'struct'
- MobX struct observable'shallow'
- MobX shallow observablefalse
- no observer
generateId()
Generates an unique identifier for a ViewModel
.
This property has default implementation here
Example
Using crypto.randomUUID()
to generate view model ids
import { viewModelsConfig } from "mobx-view-model";
viewModelsConfig.generateId = () => crypto.randomUUID();
factory()
Factory function for creating ViewModel
instances.
Can be helpful if you want to add some constructor arguments for your own ViewModel
implementation
This property has default implementation here
Example
Passing RootStore
as first constructor parameter
import { viewModelsConfig } from "mobx-view-model";
import { rootStore } from "@/shared/store";
viewModelsConfig.factory = (config) => {
const { VM } = config;
return new VM(rootStore, config);
}
fallbackComponent
A component that will be rendered while the view model is in a loading or processing state.
This is useful for showing loading spinners, skeletons, or placeholder content.
Example
viewModelsConfig.fallbackComponent = () => (
<div className="loading-spinner">
Loading...
</div>
);
onMount
A lifecycle hook that is called when a view model is mounted.
Useful for tracking component mounting, initializing external services, or setting up subscriptions.
Example
viewModelsConfig.onMount = (viewModel) => {
console.log(`ViewModel ${viewModel.id} mounted`);
// Setup analytics tracking
analytics.track('component_mounted', { id: viewModel.id });
};
onUnmount
A lifecycle hook that is called when a view model is unmounted.
Useful for cleanup operations, removing subscriptions, or tracking component lifecycle.
Example
viewModelsConfig.onUnmount = (viewModel) => {
console.log(`ViewModel ${viewModel.id} unmounted`);
// Cleanup subscriptions
viewModel.dispose();
};
processViewComponent
A higher-order function that processes and transforms the view component before it is rendered.
This function enables component composition and modification at the ViewModel level, allowing for:
- Wrapping components with additional functionality (error boundaries, providers, etc.)
- Injecting props or context
- Modifying component behavior
- Adding global features like logging, analytics, or performance monitoring
Example
viewModelsConfig.processViewComponent = (Component) => {
return (props) => {
return (
<ErrorBoundary>
<Component {...props} />
</ErrorBoundary>
)
}
}
It works only for withViewModel
HOCs
wrapViewsInObserver
Wrap View components in observer()
MobX HOC
Example:
import { viewModelsConfig } from "mobx-view-model";
viewModelsConfig.wrapViewsInObserver = true;
It works only for withViewModel
HOCs
observable
This is huge configuration object for all base implementations mobx-view-model
entities like ViewModelBase
or ViewModelStoreBase
.
You can modify default behaviour of the wrapping in makeObservable()
MobX functions.
Properties of the nested observable configs:
- disableWrapping
This is removes makeObservable(this, annotations)
/makeObservable(this)
calls
- useDecorators
This is change style of marking MobX
annotations from "decorators style" to "non decorators style".
Very helpful if you want to write code with "non decorators style".
This property has default value - true
Example:
import { observable, action } from "mobx";
import {
viewModelsConfig,
ViewModelBase,
ViewModelParams
} from "mobx-view-model";
viewModelsConfig.observable.viewModels.useDecorators = false;
class YourViewModel extends ViewModelBase {
constructor(params: ViewModelParams) {
super(params);
makeObservable(this, {
fruitName: observable,
setFruitName: action.bound,
})
}
fruitName: string = '';
setFruitName(fruitName: string) {
this.fruitName = fruitName;
}
}
Another example with "decorators style":
import { observable, action } from "mobx";
import {
viewModelsConfig,
ViewModelBase,
ViewModelParams
} from "mobx-view-model";
viewModelsConfig.observable.viewModels.useDecorators = true;
class YourViewModel extends ViewModelBase {
@observable
fruitName: string = '';
@action.bound
setFruitName(fruitName: string) {
this.fruitName = fruitName;
}
}
- custom(context, annotationsArray)
Custom function for wrapping your entity
global configuration object
You can override default global config using import viewModelsConfig
.
import { viewModelsConfig } from "mobx-view-model";
You should do this before start whole app
Usage
import { viewModelsConfig } from "mobx-view-model";
// Configure payload update\reactivity behaviour
viewModelsConfig.payloadObservable = 'ref';
viewModelsConfig.comparePayload = false;
viewModelsConfig.payloadComputed = 'struct';
// Disable view transitions
viewModelsConfig.startViewTransitions = {
mount: false,
payloadChange: false,
unmount: false,
};
// Optional configurations (uncomment to use)
// viewModelsConfig.generateId = () => crypto.randomUUID();
// viewModelsConfig.factory = (config) => new config.VM(rootStore, config);
// viewModelsConfig.fallbackComponent = () => <LoadingSpinner />;
// viewModelsConfig.onMount = (vm) => console.log('Mounted:', vm.id);
// viewModelsConfig.onUnmount = (vm) => console.log('Unmounted:', vm.id);
Possible causes of infinite rerenders due to payload access
The flexible configuration of the payload reactivity and update behavior can lead to infinite rerenders inside the View component.
This happens when the payload is changing every time the component is rerendered.
The following ViewModel configurations can cause this problem:
{
"comparePayload": false
}
{
"payloadObservable": "ref",
"comparePayload": false
}
{
"payloadObservable": "shallow",
"comparePayload": false
}
{
"payloadObservable": "deep",
"comparePayload": false
}
{
"payloadObservable": "deep",
"comparePayload": "shallow"
}
{
"payloadComputed": false,
"comparePayload": false
}
{
"payloadComputed": false,
"payloadObservable": "ref",
"comparePayload": false
}
{
"payloadComputed": false,
"payloadObservable": "shallow",
"comparePayload": false
}
{
"payloadComputed": false,
"payloadObservable": "deep",
"comparePayload": false
}
{
"payloadComputed": false,
"payloadObservable": "deep",
"comparePayload": "shallow"
}
{
"payloadComputed": true,
"comparePayload": false
}
{
"payloadComputed": true,
"payloadObservable": "ref",
"comparePayload": false
}
{
"payloadComputed": true,
"payloadObservable": "shallow",
"comparePayload": false
}
{
"payloadComputed": true,
"payloadObservable": "deep",
"comparePayload": false
}
{
"payloadComputed": true,
"payloadObservable": "deep",
"comparePayload": "shallow"
}