Skip to content

Watchers

@Watch(...propNames)

Calls the decorated method whenever the watched property changes. Receives the new and old values.

tsx
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:

tsx
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.

tsx
@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.

tsx
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.

Released under the MIT License.