Page Caching System¶
New in v0.3.0
The page caching system in Flet-Easy v0.3.0 allows you to preserve page state when navigating between routes. This is particularly useful for applications where you want to maintain ongoing processes, form data, or UI state without interruption.
Overview¶
When caching is enabled (cache=True), the page View is not reloaded when you return to it. All controls maintain their state, including:
- Form field values
- Running processes (counters, timers, etc.)
- Component state
- User interactions
Key Features¶
- State Preservation: Controls retain their values and state
- Process Continuity: Background processes continue running
- Performance Optimization: Reduces re-rendering overhead
- Seamless Navigation: Smooth user experience across pages
- Dynamic Updates: Works with
dynamic_control()for real-time updates
Basic Usage¶
Enabling Cache¶
import flet as ft
import flet_easy as fs
app = fs.FletEasy(route_init="/form")
# Enable caching for this page
@app.page("/form", title="User Form", cache=True)
def form_page(data: fs.Datasy):
# Form fields will retain their values
name_field = ft.TextField(label="Name", value="", width=200)
email_field = ft.TextField(label="Email", value="", width=200)
return ft.View(
controls=[
ft.Text("User Form (Cached)", size=24),
name_field,
email_field,
ft.ElevatedButton("Save", on_click=lambda _: print("Saved!")),
ft.ElevatedButton("go to live feed", on_click=data.go("/live-feed")),
ft.ElevatedButton("Reset", on_click=lambda _: data.page_reload())
],
vertical_alignment="center",
horizontal_alignment="center",
)
# Disable caching (default behavior)
@app.page("/live-feed", title="Live Feed")
def live_feed_page(data: fs.Datasy):
# Page resets on each visit
return ft.View(
controls=[
ft.Text("Live Feed (No Cache)", size=24),
ft.Text("This page resets every time you visit it"),
ft.ElevatedButton("go to form", on_click=data.go("/form")),
],
vertical_alignment="center",
horizontal_alignment="center",
)
app.run()
🎬 Demo¶
Advanced Example: Counter with Caching¶
This example demonstrates how caching preserves running processes:
import asyncio
import random
import flet as ft
import flet_easy as fs
app = fs.FletEasy(route_init="/")
# Remove page transition animations for smoother experience
@app.config
def config(page: ft.Page):
page.theme = ft.Theme(
page_transitions=ft.PageTransitionsTheme(
windows=ft.PageTransitionTheme.NONE,
android=ft.PageTransitionTheme.NONE,
ios=ft.PageTransitionTheme.NONE,
macos=ft.PageTransitionTheme.NONE,
linux=ft.PageTransitionTheme.NONE,
),
)
# Global view with navigation
@app.view
def config_view(data: fs.Datasy):
def change_color(e):
colors = [ft.Colors.RED, ft.Colors.GREEN, ft.Colors.BLUE, ft.Colors.YELLOW]
appbar.bgcolor = random.choice(colors)
data.page.update()
appbar = ft.AppBar(
bgcolor=ft.Colors.BLACK45,
actions=[
ft.IconButton(
icon=ft.Icons.RESTART_ALT_ROUNDED,
icon_color=ft.Colors.WHITE,
on_click=change_color,
tooltip="Change Color"
)
],
)
return fs.Viewsy(
appbar=appbar,
navigation_bar=ft.NavigationBar(
destinations=[
ft.NavigationBarDestination(icon=ft.Icons.CODE, label="Counter 1"),
ft.NavigationBarDestination(icon=ft.Icons.SYNC_DISABLED, label="Counter 2"),
ft.NavigationBarDestination(icon=ft.Icons.CODE, label="Counter 3"),
],
on_change=data.go_navigation_bar,
),
)
# Custom counter component
class Counter(ft.Container):
def __init__(self, update_func, color: str):
super().__init__()
self.update_func = update_func
self.is_running = False
self.number = ft.TextField(value="0", text_size=50, text_align="center")
self.start_button = ft.FilledButton("Start", on_click=self.toggle_counter, height=50)
self.content = ft.Column([
self.number,
self.start_button,
], horizontal_alignment="center")
self.width = 400
self.bgcolor = color
self.border_radius = 10
self.padding = 20
async def toggle_counter(self, e):
if not self.is_running:
self.is_running = True
self.start_button.text = "Stop"
self.start_button.bgcolor = ft.Colors.RED
self.update_func()
# Start counting
while self.is_running:
self.number.value = str(int(self.number.value) + 1)
self.update_func()
await asyncio.sleep(1)
else:
self.is_running = False
self.start_button.text = "Start"
self.start_button.bgcolor = None
self.update_func()
# Cached page - counter continues running when you navigate away
@app.page("/", title="Counter 1", index=0, cache=True)
def counter1_page(data: fs.Datasy):
appbar = data.view.appbar
# Dynamic title update
async def update_title(control):
control.title = ft.Text("Counter 1 - Cached")
data.dynamic_control(appbar, update_title)
return ft.View(
controls=[
ft.Text("Counter 1 (Cached)", size=50),
ft.Text("This counter keeps running when you navigate away!", size=16),
Counter(data.page.update, ft.Colors.RED_500),
],
appbar=appbar,
navigation_bar=data.view.navigation_bar,
horizontal_alignment="center",
vertical_alignment="center",
)
# Non-cached page - counter resets every time
@app.page("/counter2", title="Counter 2", index=1, cache=False)
def counter2_page(data: fs.Datasy):
appbar = data.view.appbar
appbar.title = ft.Text("Counter 2 - No Cache")
return ft.View(
controls=[
ft.Text("Counter 2 (No Cache)", size=50),
ft.Text("This counter resets every time you visit", size=16),
Counter(data.page.update, ft.Colors.BLUE_500),
],
appbar=appbar,
navigation_bar=data.view.navigation_bar,
vertical_alignment="center",
horizontal_alignment="center",
)
# Another cached page
@app.page("/counter3", title="Counter 3", index=2, cache=True)
def counter3_page(data: fs.Datasy):
appbar = data.view.appbar
# Lambda function for quick updates
data.dynamic_control(
appbar,
func_update=lambda e: setattr(e, "title", ft.Text("Counter 3 - Cached"))
)
return ft.View(
controls=[
ft.Text("Counter 3 (Cached)", size=50),
ft.Text("Another cached counter for comparison", size=16),
Counter(data.page.update, ft.Colors.GREEN_500),
],
appbar=appbar,
navigation_bar=data.view.navigation_bar,
horizontal_alignment="center",
vertical_alignment="center",
)
app.run()
🎬 Demo¶
Working with Dynamic Controls¶
When using caching, you can update shared controls dynamically using data.dynamic_control():
@app.page("/dashboard", cache=True)
def dashboard_page(data: fs.Datasy):
appbar = data.view.appbar
# Update appbar title dynamically
def update_title(control):
from datetime import datetime
current_time = datetime.now().strftime("%H:%M:%S")
control.title = ft.Text(f"Dashboard - {current_time}")
data.page.update()
# Register dynamic control
data.dynamic_control(appbar, update_title)
# Auto-update every 5 seconds
async def auto_update():
while True:
await asyncio.sleep(5)
update_title(appbar)
# Start auto-update task
data.page.run_task(auto_update)
return ft.View(
controls=[
ft.Text("Dashboard with Live Updates", size=24),
ft.ElevatedButton(
"Manual Update",
on_click=lambda _: update_title(appbar)
),
ft.ElevatedButton(
"Reset Page",
on_click=lambda _: data.page_reload()
)
],
appbar=appbar
)
Best Practices¶
When to Use Caching¶
✅ Good Use Cases:
- Forms with user input
- Pages with running processes (timers, counters)
- Complex UI state that's expensive to recreate
- Pages with ongoing data streams
- Multi-step workflows
❌ Avoid Caching When:
- Page content should always be fresh
- Real-time data that needs constant updates
- Simple static pages
- Pages with sensitive information
Performance Considerations¶
# Good: Use caching for complex forms
@app.page("/user-profile", cache=True)
def profile_page(data: fs.Datasy):
# Complex form with many fields
return ft.View(controls=[...])
# Good: No caching for simple pages
@app.page("/about", cache=False) # Default
def about_page(data: fs.Datasy):
# Simple static content
return ft.View(controls=[ft.Text("About Us")])
# Good: Reset when needed
def reset_form(_):
data.page_reload() # Clears cache and resets page
Memory Management¶
- Cached pages consume more memory
- Use
data.page_reload()to clear cache when needed - Consider the number of cached pages in your app
- Monitor memory usage in production
Troubleshooting¶
Common Issues¶
- Problem: Page doesn't update after navigation
- Solution: Use
data.dynamic_control()for shared controls
- Problem: Memory usage increasing
- Solution: Limit cached pages and use
page_reload()strategically
- Problem: Stale data in cached page
- Solution: Implement refresh mechanisms or disable caching
The page caching system in Flet-Easy v0.3.0 provides powerful state management capabilities while maintaining simplicity and performance. Use it strategically to create smooth, responsive applications that preserve user context across navigation.