self.defer() — post-render scheduling
Phoenix send(self(), :foo) parity. Schedule a callback to run AFTER the current render+patch flushes to the client. Same WS message cycle, no second re-render. Useful for analytics, audit logs, telemetry.
@action
dj-form-pending
@server_function
dj-transition
ActivityMixin
WizardMixin
dj_suspense
defer()
DataTableMixin
dj-virtual
dj-viewport
UploadMixin
Click counter
self.defer()Click the button. The counter updates immediately on render. The deferred audit-log entry is written AFTER the patch flushes — you'll see it on the next interaction (audit log re-renders then).
0
Audit log is empty. Click the button above.
The whole pattern
from djust import LiveView
class DeferDemoView(LiveView):
@event_handler()
def increment(self, **kwargs):
# Re-render fires immediately with the new count
self.click_count += 1
# Defer fires AFTER the render+patch is flushed
# to the client. Same WS message cycle, no second render.
self.defer(self._record_metric, 'click', self.click_count)
def _record_metric(self, event_name, count):
# In production: post to analytics endpoint, write audit row, etc.
# For the demo we log to a server-side list that re-appears
# on the next render (next user interaction).
self.audit_log.append({
'event': event_name, 'count': count, 'ts': time.time()
})
defer vs alternatives:
self.defer(cb, *a)— sync, after-render, no re-render. Best for fire-and-forget side effects.self.start_async(cb, *a)— background thread, re-render on completion.self.assign_async("name", loader)— background, re-render withself.name = AsyncResult(...). Best for async data loading.@backgrounddecorator — handler itself runs in background. Re-renders on completion.