ViewModelsConfig
configuration object
This object contains all global options for some behaviour of view models instances
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
.
Default library implementation is here
Example
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
Example
import { viewModelsConfig } from "mobx-view-model";
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>
)
}
}
wrapViewsInObserver
Wrap View components into observer()
MobX HOC
TIP
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 into 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".
default value is 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"
}