Watchers
@Watch(...propNames)
Calls the decorated method whenever the watched property changes. Receives the new and old values.
import { Component, State, Watch } from '@praxisjs/decorators'
import { WatchVal } from '@praxisjs/decorators'
@Component()
class Search extends StatefulComponent {
@State() query = ''
@Watch('query')
onQueryChange(newVal: WatchVal<this, 'query'>, oldVal: WatchVal<this, 'query'>) {
console.log(`query: ${oldVal} → ${newVal}`)
this.fetchResults(newVal)
}
async fetchResults(q: string) { /* ... */ }
render() {
return <input value={() => this.query}
onInput={(e) => { this.query = (e.target as HTMLInputElement).value }} />
}
}Watch multiple properties
When watching multiple props, the method receives an object with all current values:
import { WatchVals } from '@praxisjs/decorators'
@Component()
class Form extends StatefulComponent {
@State() firstName = ''
@State() lastName = ''
@Watch('firstName', 'lastName')
onNameChange(vals: WatchVals<this, 'firstName' | 'lastName'>) {
console.log(`${vals.firstName} ${vals.lastName}`)
}
}@When(propName)
Calls the decorated method exactly once, the first time the named property becomes truthy. Automatically set up on mount and cleaned up on unmount.
@Component()
class DataLoader extends StatefulComponent {
@State() data: string[] | null = null
@When('data')
onFirstLoad() {
console.log('Data arrived for the first time:', this.data)
}
render() {
return () => this.data
? <ul>{() => this.data!.map(d => <li>{d}</li>)}</ul>
: <p>Loading...</p>
}
}Use @When for one-time initialization that depends on a value arriving (e.g., first API response, user authentication).
@Until(propName)
Replaces the decorated method with one that returns a Promise resolving to the first truthy value of the named property. Each call to the method returns a fresh promise.
import { Component, State, Until } from '@praxisjs/decorators'
@Component()
class UserProfile extends StatefulComponent {
@State() user: User | null = null
@Until('user')
waitForUser(): Promise<User> { return Promise.resolve(null!) }
async loadProfile() {
const user = await this.waitForUser()
console.log('User ready:', user.name)
}
render() { /* ... */ }
}The original method body is ignored — the decorator replaces it entirely. If the property is already truthy when the method is called, the promise resolves on the next microtask.
Use @Until when downstream code needs to await a reactive value rather than react to it via a side effect.