withViewModel HOC
A Higher-Order Component that connects Solid components to their ViewModels.
No observer needed
MobX reactivity comes from mobx-solid (enableObservableTracking). Read observables directly in JSX.
API Signature
function withViewModel<TViewModel extends AnyViewModel>(
VM: Class<TViewModel>,
renderFn: (props: OriginProps & ViewModelProps<TViewModel>) => JSX.Element,
config?: ViewModelHocConfig<TViewModel>,
): VMComponent<TViewModel, OriginProps>;Configuration
getPayload
Sets the payload for the ViewModel attached to the view.
Default: (props) => props.payload
Example — all props as payload:
class VM extends ViewModelBase {
get foo() {
return this.payload.foo;
}
}
export const YourComponent = withViewModel(
VM,
() => <div>1</div>,
{ getPayload: (props) => props },
);
<YourComponent foo={"1"} />Prefer withPropsViewModel for this pattern.
factory
Factory for creating ViewModel instances.
Same as factory in viewModelsConfig
id
Unique identifier for the view.
solidHook
Extra Solid reactive setup inside the resulting component (runs during component setup).
import { withViewModel, type WithViewModelSolidHook } from "mobx-view-model-solid";
const useExtraSetup: WithViewModelSolidHook = (props) => {
// Solid createEffect / createMemo / etc.
};
const Component = withViewModel(YourVM, () => <div>1</div>, {
solidHook: useExtraSetup,
});Falls back to viewModelsConfig.reactHook if solidHook is omitted (shared callback shape).
fallback
Component to render while the view model is mounting.
class YourVM extends ViewModelBase {
async mount() {
await fetchData();
super.mount();
}
}
const Component = withViewModel(YourVM, () => <div>1</div>, {
fallback: () => <div>loading...</div>,
});vmConfig
Additional ViewModel configuration.
See viewModelsConfig
ctx
Static unique data for this HOC call.
anchors
Additional Solid component anchors for the same VM instance.useViewModel(AnchorComponent) returns this VM when the connected component is mounted.
const Anchor = () => null;
const Component = withViewModel(VM, View, {
anchors: [Anchor],
});
// useViewModel(Anchor) → same VM as View receivesconnect(anchor)
Registers additional anchors dynamically.
const Anchor = () => null;
const Component = withViewModel(VM, View).connect(Anchor);
const model = useViewModel(Anchor);Usage
Basic
import { ViewModelBase } from "mobx-view-model";
import { ViewModelProps, withViewModel } from "mobx-view-model-solid";
import { observable, action } from "mobx";
class VM extends ViewModelBase {
@observable
accessor value = "";
@action
setValue = (value: string) => {
this.value = value;
};
}
export const YourComponent = withViewModel(VM, (props: ViewModelProps<VM>) => (
<div>
<input
value={props.model.value}
onInput={(e) => props.model.setValue(e.currentTarget.value)}
/>
</div>
));Custom configuration
export const YourComponent = withViewModel(VMClass, ViewComponent, {
vmConfig: {},
ctx: {},
factory: (config) => new config.VM(config),
fallback: () => <div>loading</div>,
getPayload: (props) => props.payload,
id: "unique-id",
anchors: [],
solidHook: (allProps, ctx, viewModels) => {},
});Notes
- Solid component functions run once; keep MobX reads in JSX / Solid computations.
- Prefer not destructuring Solid
propsif you need them to stay reactive forgetPayloadupdates — the HOC passes an accessor() => getPayload(allProps)intouseCreateViewModel.
