Lifecycle Methods
Lifecycle methods allow you to run code at specific times in a component’s life.
Mounting
Methods called when a component is being added to the DOM:
component_did_mount()
Called immediately after the component is mounted. Use this for:
Fetching data
Setting up subscriptions
Adding event listeners
class DataFetcher(Component):
def __init__(self, props):
super().__init__(props)
self.state = {'data': None, 'loading': True}
def component_did_mount(self):
# Fetch data when component mounts
self.fetch_data()
async def fetch_data(self):
# Simulated data fetch
import asyncio
await asyncio.sleep(1)
self.setState({
'data': {'message': 'Hello from API'},
'loading': False
})
def render(self):
if self.state['loading']:
return element('div', {}, 'Loading...')
return element('div', {}, self.state['data']['message'])
Updating
Methods called when a component is being re-rendered:
component_did_update(prev_props, prev_state)
Called after the component updates. Use this for:
Responding to prop changes
Network requests based on new data
DOM updates
class UserProfile(Component):
def component_did_update(self, prev_props, prev_state):
# Fetch new data when user ID changes
if prev_props.get('userId') != self.props.get('userId'):
self.fetch_user_data()
def fetch_user_data(self):
user_id = self.props['userId']
print(f'Fetching data for user {user_id}')
def render(self):
return element('div', {}, f'User: {self.props["userId"]}')
should_component_update(nextProps, nextState)
Called before rendering. Return False to skip rendering:
class ExpensiveComponent(Component):
def should_component_update(self, next_props, next_state):
# Only update if data actually changed
return self.props['data'] != next_props['data']
def render(self):
# Expensive rendering operation
return element('div', {}, 'Expensive content')
Unmounting
Methods called when a component is being removed from the DOM:
component_will_unmount()
Called immediately before the component is unmounted. Use this for:
Cleaning up subscriptions
Canceling network requests
Removing event listeners
class Timer(Component):
def __init__(self, props):
super().__init__(props)
self.state = {'seconds': 0}
self.timer_id = None
def component_did_mount(self):
self.timer_id = self.start_timer()
def component_will_unmount(self):
# Clean up timer
if self.timer_id:
self.stop_timer(self.timer_id)
def start_timer(self):
import threading
def tick():
self.setState({'seconds': self.state['seconds'] + 1})
timer = threading.Timer(1.0, tick)
timer.start()
return timer
def stop_timer(self, timer_id):
timer_id.cancel()
def render(self):
return element('div', {}, f'Seconds: {self.state["seconds"]}')
Error Handling
Methods for handling errors during rendering:
component_did_catch(error, info)
Called when an error is thrown during rendering:
class ErrorBoundary(Component):
def __init__(self, props):
super().__init__(props)
self.state = {'has_error': False, 'error': None}
def component_did_catch(self, error, info):
# Log error to service
print(f'Error: {error}')
print(f'Info: {info}')
self.setState({
'has_error': True,
'error': error
})
def render(self):
if self.state['has_error']:
return element('div', {'class': 'error'},
element('h2', {}, 'Something went wrong'),
element('p', {}, str(self.state['error']))
)
return self.props.get('children', [])
Lifecycle Diagram
Mounting:
constructor → render → component_did_mount
Updating:
new props/state → should_component_update → render → component_did_update
Unmounting:
component_will_unmount
Best Practices
Clean up in will_unmount - Always clean up subscriptions and timers
Avoid side effects in constructor - Use
component_did_mountinsteadUse should_component_update - Optimize performance for expensive renders
Handle errors - Use error boundaries for better error handling
Next Steps
Component API - Component API reference
Testing - Test lifecycle methods
State - Learn about state management