GlyphUI components go through a lifecycle from creation to destruction. During this lifecycle, specific methods are called at key moments, allowing you to run code at specific times.The component lifecycle has three main phases:
Mounting - Component is being created and inserted into the DOM
Updating - Component is being re-rendered due to prop or state changes
Unmounting - Component is being removed from the DOM
Called immediately before the component is mounted to the DOM. The virtual DOM has been created but not yet rendered.
class DataFetcher extends Component { beforeMount() { console.log('Component is about to mount'); // Good place to prepare data or set flags this.setState({ isLoading: true }); } render(props, state) { return h('div', {}, [ state.isLoading ? 'Loading...' : 'Content' ]); }}
Use cases for beforeMount():
Initialize non-reactive properties
Set loading states
Prepare data before first render
State changes in beforeMount() will be included in the initial render, avoiding an extra re-render.
Called after the component has been mounted and the DOM elements are available. This is the most commonly used lifecycle method.From packages/runtime/src/component.js:67-86, here’s when it’s called:
mount(parentEl) { this.parentEl = parentEl; // Call lifecycle method before first render if (this.beforeMount) { this.beforeMount(); } // Initial render this.vdom = this._renderWithSlots(); mountDOM(this.vdom, parentEl); this.isMounted = true; // Called after mounting ✓ if (this.mounted) { this.mounted(); } return this;}
Example usage:
class TimerComponent extends Component { constructor(props) { super(props, { initialState: { seconds: 0 } }); this.intervalId = null; } mounted() { console.log('Component mounted'); console.log('DOM element:', this.vdom.el); // Start interval after component is in the DOM this.intervalId = setInterval(() => { this.setState(state => ({ seconds: state.seconds + 1 })); }, 1000); } render(props, state) { return h('div', {}, [`Seconds: ${state.seconds}`]); }}
Use cases for mounted():
Fetch data from APIs
Set up subscriptions or timers
Integrate with third-party libraries
Access DOM elements directly
Set up event listeners
From examples/component-demo/component-demo.js:14-16:
mounted() { console.log(`Counter mounted with initial count: ${this.state.count}`);}
Called after the component has re-rendered and the DOM has been updated. This is the update equivalent of mounted().From packages/runtime/src/component.js:117-138, here’s the update flow:
updateProps(newProps) { const oldProps = this.props; this.props = { ...this.props, ...newProps }; // Extract slot content from new props.children if (newProps.children && Array.isArray(newProps.children)) { this.slotContents = extractSlotContents(newProps.children); } // Called before update ✓ if (this.beforeUpdate) { this.beforeUpdate(oldProps, this.props); } // Re-render with new props this._renderComponent(); // Called after update ✓ if (this.updated) { this.updated(oldProps, this.props); }}
Example usage:
class ScrollToTop extends Component { updated(oldProps, newProps) { console.log('Component updated'); // Scroll to top when page prop changes if (oldProps.page !== newProps.page) { window.scrollTo(0, 0); } } render(props) { return h('div', {}, [`Page ${props.page}`]); }}
Use cases for updated():
Interact with updated DOM
Trigger animations
Update third-party libraries
Respond to prop changes
Log analytics events
Be careful not to call setState() unconditionally in updated() - this will cause an infinite loop!
Called after the component has been unmounted and destroyed. The DOM elements have been removed.From packages/runtime/src/component.js:91-111, here’s the unmount flow:
unmount() { // Called before unmounting ✓ if (this.beforeUnmount) { this.beforeUnmount(); } // Clean up DOM if (this.vdom) { destroyDOM(this.vdom); this.vdom = null; } // Clean up subscriptions this._subscriptions.forEach(unsubscribe => unsubscribe()); this.isMounted = false; // Called after unmounting ✓ if (this.unmounted) { this.unmounted(); }}
Calling setState() in render() causes an infinite loop. Only call it in lifecycle methods or event handlers.
// ✗ BAD - Infinite looprender() { this.setState({ count: 1 }); return h('div', {}, []);}// ✓ GOOD - Call in lifecycle methodmounted() { this.setState({ count: 1 });}
Be Careful with setState() in updated()
Always use a condition when calling setState() in updated(), or you’ll create an infinite loop.
// ✗ BAD - Infinite loopupdated() { this.setState({ timestamp: Date.now() });}// ✓ GOOD - Conditional updateupdated(oldProps, newProps) { if (oldProps.userId !== newProps.userId) { this.setState({ isLoading: true }); }}
Use beforeMount() for Initial Setup
Use beforeMount() for setup that should happen before the first render, preventing an extra re-render.
// ✓ Better - No extra renderbeforeMount() { this.setState({ isLoading: true });}// ✗ Works but causes extra rendermounted() { this.setState({ isLoading: true });}