import solara
from local_storage import LocalStorage
from solara_cache import use_cache, init_cache
from typing import Literal
"""
In this experiment I look at two methods of caching the state
1) By using solara's built in cache storage
2) By using local storage (i.e. the browser's local storage)
Which one is best depends on where how much you need to persist.
## Solara Cache
- Stored in server memory
- Cleared when the server restarts
- Shared across instances/tabs if connected to the same server
## Browser Local Storage
The browser's local storage persists across server restarts
### sessionStorage vs localStorage
- sessionStorage
- is only available for the current tab
- is cleared when the tab is closed
- if a tab is duplicated, the new tab will have its own sessionStorage, but (possibly) copy the original tab's sessionStorage
- localStorage
- is available across all tabs and windows
- is cleared when the browser is closed
- if a tab is duplicated, the new tab will share the same localStorage as the original tab
- if >1 tab is open, must refresh the tabs to see changes made in other tabs
"""
CACHE_NAME = 'test-cache'
init_cache(CACHE_NAME) # Initialize the cache if it doesn't exist
def safeInt(val: int | str | Literal['null']):
if val == 'null' or val is None:
return 0
else:
try:
return int(val)
except TypeError:
print(f"ValueError: Cannot convert {val} to int")
return -999
@solara.component
def Page():
solara.lab.theme.dark = True
print("Page")
# color = solara.use_reactive("green")
color = "green"
local_storage_clicks = solara.use_reactive(0)
def increment_local_storage():
print("Incrementing local storage")
local_storage_clicks.value += 1
solara_cache_clicks = solara.use_reactive(0)
def increment_solara_cache():
print("Incrementing solara cache")
solara_cache_clicks.value += 1
def increment():
print("Incrementing")
local_storage_clicks.value += 1
solara_cache_clicks.value += 1
#### Local Storage
showDebug = solara.use_reactive(True)
# clear_local_storage = solara.use_reactive(False)
clear_local_storage = solara.use_reactive(0)
LocalStorage(key = "clicks",
value = local_storage_clicks.value,
on_value=lambda v: local_storage_clicks.set(safeInt(v)),
sessionOnly=False, # if true will persist across sessions (i.e. tabs)
clear=clear_local_storage.value,
debug=showDebug.value)
#### Solara Cache
# need to do this in a use_effect to avoid
# calling it each time the component re-renders
def _cache_value():
def set_from_cache(val):
print("Setting from cache", val)
solara_cache_clicks.set(safeInt(val))
use_cache(key="clicks",
reactive_value=solara_cache_clicks,
on_value=set_from_cache,
default=0,
cache_name=CACHE_NAME
)
solara.use_effect(_cache_value, dependencies=[])
cache = solara.cache.storage[CACHE_NAME]
def reset_solara_cache():
solara.cache.storage[CACHE_NAME] = {}
solara.Text(f"Solara '{CACHE_NAME}': {cache}", classes=['debug'])
force_rerender = solara.use_reactive(0)
force_rerender.value # call this here to force the full component to render
# rather than just stuff in the Div
def reset():
print('Setting both to zero')
local_storage_clicks.value = 0
solara_cache_clicks.value = 0
reset_solara_cache()
clear_local_storage.set(clear_local_storage.value + 1)
### UI
with solara.Div(classes=['mx-2']):
with solara.Column():
solara.Text(f"Clicks (LocalStorage): {local_storage_clicks.value}")
solara.Text(f"Clicks (Cache): {solara_cache_clicks.value}")
with solara.Column(align="start"):
solara.Button(label=f"Increment Both", on_click=increment, color='#4c0a8a')
with solara.Row(justify="center"):
solara.Button(label=f"Increment LocalStorage",
on_click=increment_local_storage,
color='black')
solara.Button(label=f"Increment Cache",
on_click=increment_solara_cache,
color='black')
solara.Row()
with solara.Column(align="start"):
solara.Button(label="Reset", on_click=reset, color="#8a0a28")
with solara.Row(justify="center"):
solara.Button(label="Clear Local Storage",
on_click=lambda: clear_local_storage.set(clear_local_storage.value + 1)
, color="#8a0a28")
solara.Button(label="Clear Solara Cache",
on_click=reset_solara_cache, color="#8a0a28")
solara.Button(label=f"Force Rerender: {force_rerender.value}",
on_click=lambda: force_rerender.set(force_rerender.value + 1), color="grey")
# solara.Button(label="Toggle Debug", on_click=lambda: showDebug.set(not showDebug.value))