Model State Guide
This guide explains how model-based server-data state works in Zova within the Cabloy monorepo.
Why the model layer exists
Zova uses model-based state management on top of API access so remote data can participate in a more unified caching and usage model.
This improves runtime performance and developer experience by building on top of TanStack Query rather than exposing only raw request flows.
Create a model
Example: create a model named menu in module demo-student.
npm run zova :create:bean model menu -- --module=demo-studentModel definition
Representative pattern:
@Model()
export class ModelMenu {
retrieveMenus() {
return this.$useStateData({
queryKey: ['retrieveMenus'],
queryFn: async () => {
return await this.$api.homeBaseMenu.retrieveMenus({
params: { publicPath: '' },
});
},
});
}
}This pattern is important because it shows that model logic is not just local state. It is also the place where cached remote data becomes a reusable abstraction.
Using a model
Representative pattern:
@Use()
$$modelMenu: ModelMenu;
protected render() {
const { data, error } = this.$$modelMenu.retrieveMenus();
if (error) return <div>{error.message}</div>;
return <div>{data}</div>;
}Relationship to the server-data ladder
In the new docs, think about the layers like this:
$fetch→ direct request access$api→ business-oriented service methodsModel→ cached, reusable, UI-friendly remote state
That makes the model layer one of the most important bridges between backend contracts and frontend rendering.
Implementation checks for model-based state changes
When you see repeated frontend data usage, caching concerns, or UI state that depends on remote data, ask whether the right abstraction is a model instead of a direct API call in the page.
That usually leads to cleaner SSR behavior, cleaner reuse, and a more Cabloy-native structure.