Lifecycle Hooks
PraxisJS components expose four lifecycle hooks — onBeforeMount, onMount, onUnmount, and onError — available on both StatefulComponent and StatelessComponent.
Lifecycle Hooks
All lifecycle hooks are inherited from the base component class, so they're available on both StatefulComponent and StatelessComponent. Override any of them to tap into the component's lifecycle.
npm install @praxisjs/core @praxisjs/decoratorspnpm add @praxisjs/core @praxisjs/decoratorsyarn add @praxisjs/core @praxisjs/decoratorsbun add @praxisjs/core @praxisjs/decoratorsLifecycle diagram
[created] → onBeforeMount() → [DOM rendered] → onMount() → [in use]
↓
onUnmount() → [destroyed]
↑ error ↓
onError(err)onBeforeMount()
Called before the component's DOM is created. The DOM is not yet available at this point.
Use it to initialize state before the first render — for example, setting a @State field from a @Prop value:
@Component()
class Counter extends StatefulComponent {
@Prop() initialCount = 0
@State() count = 0
onBeforeMount() {
this.count = this.initialCount
}
render() {
return <div>{() => this.count}</div>
}
}onMount()
Called after the component is inserted into the DOM. The DOM elements are fully available.
Use it to:
- Access DOM elements captured via
ref - Start timers or intervals
- Subscribe to external events
- Kick off data fetches that require the DOM
@Component()
class Timer extends StatefulComponent {
@State() elapsed = 0
private interval?: ReturnType<typeof setInterval>
onMount() {
this.interval = setInterval(() => this.elapsed++, 1000)
}
onUnmount() {
clearInterval(this.interval)
}
render() {
return <p>{() => this.elapsed}s elapsed</p>
}
}onUnmount()
Called when the component is removed from the DOM. Clean up everything you set up in onMount:
onMount() {
this.interval = setInterval(() => this.tick(), 1000)
window.addEventListener('resize', this.onResize)
this.observer = new ResizeObserver(this.handleResize)
this.observer.observe(this.el)
}
onUnmount() {
clearInterval(this.interval)
window.removeEventListener('resize', this.onResize)
this.observer.disconnect()
}Composables clean up automatically
If you're using @Compose with a composable like WindowSize or ScrollPosition, you don't need to manually clean up — composables hook into onMount and onUnmount automatically.
onError(error)
Called when an error is thrown inside render(). If onError returns a Node, Node[], or null, that result is mounted as fallback DOM — this is PraxisJS's error boundary model.
Returning fallback DOM
The simplest pattern: return nodes directly from onError and they replace the failed component output.
@Component()
class SafeCard extends StatefulComponent {
onError(err: Error) {
return <p class="error-fallback">Failed to load: {err.message}</p>
}
render() {
return <Card data={this.data} />
}
}Return null (or void) to silently suppress the error — the component renders nothing:
onError(err: Error) {
reportToMonitoring(err)
return null
}Callback to parent + retry
onError can also notify a parent component via a prop callback, letting the parent own the recovery UI and remount the child on retry:
@Component()
class RemoteCard extends StatelessComponent<{ attempt: number; onFail: (e: Error) => void }> {
onError(err: Error) {
this.props.onFail(err)
return null
}
render() { /* ... */ }
}Reactive fallback with @State
When you need the fallback to be interactive (e.g. a retry button), store the error in state and branch inside render():
@Component()
class SafeLoader extends StatefulComponent {
@State() error: Error | null = null
onError(err: Error) {
this.error = err
}
render() {
return () => this.error
? <p class="error">Something went wrong: {() => this.error!.message}</p>
: <DataView />
}
}JSX in onError
JSX is valid inside onError — it compiles to ordinary node-creation calls. The result is static (not reactive), which is fine for error states.
Lifecycle in StatelessComponent
Lifecycle hooks work the same way in StatelessComponent — no @State required:
@Component()
class Banner extends StatelessComponent<{ text: string }> {
onMount() {
console.log('Banner mounted with text:', this.props.text)
}
onUnmount() {
console.log('Banner removed')
}
render() {
return <div class="banner">{this.props.text}</div>
}
}Combining lifecycle with @Watch
@Watch runs after mount automatically. Use onMount when you need DOM access first:
@Component()
class AutoFocus extends StatefulComponent {
private inputEl: HTMLInputElement | null = null
onMount() {
this.inputEl?.focus()
}
render() {
return <input ref={(el) => { this.inputEl = el }} />
}
}What's next?
- Async Data — data fetching with
@Resourceand reactive refetching - Decorators: Watchers —
@Watch,@When,@Untilfor reactive side effects - Composables: DOM —
WindowSize,ScrollPosition, and more — all lifecycle-managed automatically
JSX Syntax
PraxisJS uses a custom JSX runtime. Learn how to write reactive templates, handle events, use fragments, and map lists.
Async Data
@Resource is PraxisJS's decorator for binding async data to a component field — it tracks loading, error, and data state reactively, with automatic refetch, cancel, mutate, shared cache, and stale-while-revalidate.