smalljs$molSearch⌘ KDocsPlaygroundCompareEcosystemAboutEN
Mental modelGetting StartedIntroductionMental modelGetting StartedFrom TypeScript to view.treeProject StructureToolingEssentialsInstallationViewsState & ReactivityRoutingRenderingTestingDeploymentTroubleshootingDataData FetchingData SchemasGiper BazaMoreShowcaseFrom React, Vue & SvelteCookbookAdvancedPluginsModule metadataOfflineGhost viewsAboutFAQTeamReleasesAPI$mol_button_major$mol_button_minor$mol_string$mol_number$mol_text$mol_paragraph$mol_list$mol_row$mol_link$mol_check$mol_switch$mol_select$mol_scroll$mol_page$mol_pick

Mental model

If you come from React or Vue, the first days in $mol are spent looking for things that are not there: computed, watch, useEffect, onMounted, a fetch in a lifecycle hook. They are not hidden somewhere in the API; the model has no place for them. This page is the five-minute version of that model. Read it before Views, and come back when a familiar name goes missing.

Pull, not push

Nothing is computed until someone reads it. A view renders by reading its properties; each property reads whatever it needs; the dependency chain assembles itself from those reads. There is no subscription to declare and no watch to register: the read is the subscription.1$my_profile $mol_view2 sub /3 <= Name $mol_view4 sub / <= name \1namespace $.$$ {2 export class $my_profile extends $.$my_profile {3 @ $mol_mem4 user() {5 return this.$.$mol_fetch.json( 'https://api.example.com/me' ) as { name: string }6 }7 name() {8 return this.user().name9 }10 }11}Rendering Name reads name(), name() reads user(), user() hits the network. Nobody told the view about the request and nobody told the request about the view. When user() changes, everything that read it recomputes, and nothing else does.

No lifecycle

There is no mounted, no useEffect, no created. Data is requested by reading a property, and a view reads its properties when it renders. So the example above loads the user the moment $my_profile appears on screen, and not before. When the view leaves the screen, nothing reads user() any more, and the cell is released along with the view.That is the whole replacement for the "fetch on mount" pattern: the view asks for what it needs, and the framework decides when to ask. Loading is not attached to a page event; it is attached to being visible.

A property is a cell

One method with an optional argument is at once getter, setter, computed value and state:1@ $mol_mem2count( next?: number ) {3 return next ?? 04}Called without an argument it reads, called with one it writes. @ $mol_mem turns the method into a cached cell that recomputes when something it read has changed. A computed value is just a @ $mol_mem method that reads other methods. A watcher is not needed: a side effect belongs to an event, and an event handler is a method marked @ $mol_action.1@ $mol_mem2doubled() {3 return this.count() * 24}5 6@ $mol_action7increment() {8 this.count( this.count() + 1 )9}
Edit this page on GitHubWas this helpful?YesNoPreviousIntroductionNextGetting Started
On this pagePull, not pushNo lifecycleA property is a cellSync code that waitsEverything is an overrideHow to read the sourcesNamesNext
Type to search the documentation.