Data & Queries
Optimistic Mutation
Show instant feedback when users perform actions, then sync with the server. This avoids the "laggy" feeling of waiting for server responses before updating the UI.
Recipe
import asyncio
from typing import TypedDict
import pulse as ps
class User(TypedDict):
id: int
name: str
class UserState(ps.State):
user_id: int = 1
@ps.query
async def user(self) -> User:
await asyncio.sleep(0.5) # Simulated API call
return {"id": self.user_id, "name": f"User {self.user_id}"}
@user.key
def _user_key(self):
return ("user", self.user_id)
async def rename(self, new_name: str):
# 1. Optimistically update the UI immediately
self.user.set_data({"id": self.user_id, "name": new_name})
# 2. Persist to server (your actual API call)
await asyncio.sleep(0.3)
# 3. Refetch to reconcile with server state
await self.user.refetch()
@ps.component
def UserProfile():
with ps.init():
state = UserState()
async def handle_rename():
await state.rename("New Name")
return ps.div(
ps.p(f"Name: {state.user.data['name']}" if state.user.data else "Loading..."),
ps.button("Rename", onClick=handle_rename),
)How it works
set_data()immediately updates the cached query data, so the UI reflects the change- Your server-side logic runs in the background
refetch()gets the authoritative state from the server
If the server returns different data (e.g., validation changed the name), the UI automatically updates to match.
Handling errors
If the server call fails, refetch to restore the original state:
async def rename(self, new_name: str):
old_data = self.user.data
self.user.set_data({"id": self.user_id, "name": new_name})
try:
await api_rename(self.user_id, new_name)
await self.user.refetch()
except Exception:
# Rollback on failure
self.user.set_data(old_data)