ViewModel interface
Interface that defines the core functionality for implementing the MVVM pattern in your application.
All code examples will include the base implementation of this interface.
API Signature
interface ViewModel<Payload, ParentViewModel>Generics
1. Payload
Declares the payload data type for your ViewModel. Used for transferring data between view models or views.
Must be an object type or EmptyObject for no payload.
2. ParentViewModel
Declares the parent ViewModel type where current ViewModel is rendered in the component hierarchy.
Enables access to parent view model through the parentViewModel property.
Optional, defaults to null if not specified.
Core Properties
id: string
Unique identifier for the view model instance.
Used for tracking and managing view model lifecycle.
vmConfig: ViewModelsConfig
Configuration object for the view model.
See ViewModelsConfig for detailed configuration options.
payload: Payload
Data object passed from the parent component to the view model.
isMounted: boolean
Indicates whether the ViewModel is currently mounted with its associated component.
Controls the rendering of the connected view component:
true: Component is renderedfalse: Component is not rendered
isUnmounting: boolean
Indicates whether the ViewModel is in the process of unmounting.
Used for cleanup and transition states during component unmounting.
parentViewModel: ParentViewModel | null
Reference to the parent ViewModel in the component hierarchy.
WARNING
This property is only available when using:
ViewModelStore(integrated with ViewModelsProvider)withViewModelHOC
Example: Parent-Child ViewModel Communication
import { ViewModelBase } from "mobx-view-model";
class ParentVM extends ViewModelBase {
foo = 'bar'
}
class ChildVM extends ViewModelBase<{}, ParentVM> {
get baz() {
return this.parentViewModel?.foo; // 'bar'
}
}Lifecycle Methods
mount(): void | Promise<void>
Called when the component is mounted in the React tree.
TIP
The behavior depends on your ViewModelStore implementation.
Base implementation sets isMounted to true after this method.
TIP
Can return a Promise for asynchronous mounting operations.
Example: Async Mounting
import { ViewModelBase } from "mobx-view-model";
class JediProfileVM extends ViewModelBase<{ jediId: string }> {
async mount() {
await this.loadJediData();
await super.mount();
}
private async loadJediData() {
const response = await fetch(`/api/jedi/${this.payload.jediId}`);
this.jediData = await response.json();
}
}unmount(): void | Promise<void>
Called when the component is unmounted from the React tree.
TIP
Behavior depends on your ViewModelStore implementation.
Base implementation sets isMounted to false after this method.
TIP
Can return a Promise for asynchronous cleanup operations.
Payload Management
setPayload(payload: Payload): void
Updates the view model's payload data.
React integration
useCreateViewModel and withViewModel can call setPayload on every render while the component is in the tree. That includes moments before mount() has run or finished — so isMounted may still be false. Do not assume a fully mounted view model inside setPayload, payloadChanged, or logic they trigger (e.g. avoid starting work that must only run after mount() unless you guard on isMounted).
TIP
When extending ViewModelBase, do not assign to this.payload directly (it is a getter): call super.setPayload(payload) or override payloadChanged().
Example: Payload Update with Validation
import { ViewModelBase } from "mobx-view-model";
import { runInAction } from "mobx";
class LightsaberVM extends ViewModelBase<{ jediId: string }> {
@observable
accessor currentJediId: string | null = null;
setPayload(payload: { jediId: string }) {
if (this.currentJediId !== payload.jediId) {
runInAction(() => {
this.currentJediId = payload.jediId;
});
super.setPayload(payload);
}
}
}payloadChanged(payload: Payload, prevPayload: Payload): void
Called when the payload is updated via setPayload().
Use this method to handle payload changes and trigger necessary updates.
Example: Handling Payload Changes
import { ViewModelBase } from "mobx-view-model";
import { runInAction } from "mobx";
class DeathStarVM extends ViewModelBase<{ targetId: string }> {
@observable
accessor currentTargetId: string | null = null;
payloadChanged(payload, prevPayload) {
if (this.currentTargetId !== payload.targetId) {
runInAction(() => {
this.currentTargetId = payload.targetId;
this.initializeWeapon();
});
}
}
private async initializeWeapon() {
const response = await fetch(`/api/weapons/${this.currentTargetId}`);
this.weaponData = await response.json();
}
}