"Commands are a question and an answer. Events are an announcement nobody had to ask for."
Push, Not Pull
Sometimes the core has news the frontend didn't request: a download finished, a watched file changed, a timer ticked, a tray menu was clicked. Polling for that with commands is wasteful. Instead the core emits an event and the frontend listens. app.emit("name", payload) broadcasts to all webviews; the frontend's listen("name", handler) (from @tauri-apps/api/event) receives each one with its payload. The payload is any serializable value, serde-encoded just like command data.
Broadcast vs Target
emit sends to everyone. When you have multiple windows and only one should hear it, emit_to("window-label", "name", payload) targets a specific webview. Events also flow the other direction — the frontend can emit and Rust can listen — but for frontend-to-core requests you usually want a command (you get a return value and error handling). Reserve events for fire-and-forget announcements.
Always Clean Up Listeners
listen returns a function that removes the listener. In a component, register in an effect and call that unlisten function on cleanup, or you'll stack duplicate handlers every time the component mounts — the classic memory-leak-and-double-fire bug. Use once for events you only ever want to handle a single time.