new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Tauri · Develop · all subjects

ipc/events

43 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Events are bidirectional in Tauri IPC

Events are one-way, fire-and-forget IPC messages that can be emitted by both the Frontend and the Tauri Core, unlike Commands which are unidirectional from Frontend to Core.

Listen to plugin events from JavaScript

Listen to plugin events from JavaScript using addPluginListener: ```javascript import { addPluginListener, PluginListener } from '@tauri-apps/api/core'; export async function onRequest( handler: (url: string) => void ): Promise<PluginListener> { return await addPluginListener( '<plugin-name>', 'event-name', handler ); } ```

Android plugin event with trigger

Emit events from an Android plugin using the trigger function: ```kotlin @TauriPlugin class ExamplePlugin(private val activity: Activity): Plugin(activity) { override fun load(webView: WebView) { trigger("load", JSObject()) } override fun onNewIntent(intent: Intent) { if (intent.action == Intent.ACTION_VIEW) { val data = intent.data.toString() val event = JSObject() event.put("data", data) trigger("newIntent", event) } } @Command fun openCamera(invoke: Invoke) { val payload = JSObject() payload.put("open", true) trigger("camera", payload) } } ```

iOS plugin event with trigger

Emit events from an iOS plugin using the trigger function: ```swift class ExamplePlugin: Plugin { @objc public override func load(webview: WKWebView) { trigger("load", data: [:]) } @objc public func openCamera(_ invoke: Invoke) { trigger("camera", data: ["open": true]) } } ```

Listen to webview-specific events from frontend

Use `getCurrentWebviewWindow()` from `@tauri-apps/api/webviewWindow` to get the current webview, then call its `listen` method to listen to webview-specific events. This is similar to global event listening but scoped to a single webview.

listen function returns a Promise to the unlisten handle

The `listen` function returns a Promise that resolves to the `unlisten` function. The `unlisten` function must be awaited before calling it to properly unregister the listener.

Unlisten keeps event listener registered for entire application lifetime

The `listen` function keeps the event listener registered for the entire lifetime of the application. To stop listening, call the `unlisten` function returned by `listen`.

Call unlisten after Promise resolves, not before

Never call `unlisten()` synchronously before the `listen` Promise resolves. If called too early, the handler will be removed immediately and no events will be received. Always await the Promise first to get the actual unlisten function.

Event listener timing in setup hooks

In frameworks like React, Vue, and Svelte, setup or mount hooks run before the component is fully rendered. If you listen for events during setup, the event handler may depend on DOM elements that haven't been rendered yet. Defer listener registration to an effect/hook that runs after mount.

Event ordering with async listeners

Event listeners are called in the order they are registered, but if a listener is async and the event emitter sends multiple events in rapid succession, listeners may process events out of order. For ordered, high-throughput data delivery, use Channels instead of the event system.

Clean up event listeners in component unmount

When using a frontend framework, clean up event listeners when a component is unmounted to avoid memory leaks and duplicate handlers. Use framework-specific cleanup hooks like useEffect return, onUnmounted, or Svelte effects.

Listen to event exactly once with once function

The `once` function from `@tauri-apps/api/event` listens to an event exactly one time and automatically unregisters the listener after the first trigger. Available for both global and webview-specific events via `getCurrentWebviewWindow().once()`.

React event listener cleanup example

In React, use `useEffect` with a cleanup function that awaits the `unlisten` promise and calls the returned function. Example: `useEffect(() => { const unlisten = listen<number>('download-progress', (event) => { setProgress(event.payload); }); return () => { unlisten.then((fn) => fn()); }; }, []);`

Vue event listener cleanup example

In Vue, store the `listen` promise in a variable during `onMounted`, then call `unlistenPromise?.then((fn) => fn())` in the `onUnmounted` hook. Example stores `unlistenPromise` outside the lifecycle hooks and cleans it up on unmount.

Svelte event listener cleanup example

In Svelte, use the `$effect` function to set up the listener and return a cleanup function that awaits the `unlisten` promise and calls the returned function. Example: `$effect(() => { const unlistenPromise = listen<number>('download-progress', (event) => { progress = event.payload; }); return () => { unlistenPromise.then((unlisten) => unlisten()); }; });`

Listen to global events from Rust

Use the `app.listen()` method in Rust to listen to global events. The method takes an event name as a string and a closure that receives an event object. Access the event payload using `event.payload()` which returns a string that can be deserialized.

Listen to webview-specific events from Rust

Use `app.get_webview_window("main")` to get a webview, then call `webview.listen()` to listen to webview-specific events. The event object has a `data` property containing the event data.

Rust event listener registration lifetime

The Rust `listen` function keeps the event listener registered for the entire lifetime of the application. To stop listening, call `app.unlisten(event_id)` where `event_id` is returned by the `listen` call.

Rust unlisten by event ID or inside handler

In Rust, unlisten using two approaches: (1) store the event_id returned by `listen()` and call `app.unlisten(event_id)`, or (2) inside the event handler, call `handle.unlisten(event.id)` when a condition is met to remove the listener immediately after.

Automatic listener cleanup on page reload or URL navigation

When the page is reloaded or you navigate to another URL, listeners are automatically unregistered. This does not apply to Single Page Application (SPA) routers.

Rust listen once with once function

Use `app.once()` to listen to an event exactly once in Rust. The listener is immediately unregistered after its first trigger.

Frontend and Rust share the same event system

Events emitted in the frontend also trigger listeners registered by the Rust APIs, and vice versa. Both frontend and Rust can listen to and emit events on the same channels.

Listen to global events from frontend

Use the `listen` function from `@tauri-apps/api/event` to listen to global events emitted from Rust. The function accepts a generic type parameter for the event payload and a callback that receives an event object. The event object has a `payload` property containing the emitted data.

Emit global events from frontend

Use emit() from @tauri-apps/api/event to trigger a global event that all listeners receive: import { emit } from '@tauri-apps/api/event'; emit('file-selected', '/path/to/file');

Emit webview-specific events from frontend

Use emitTo() to trigger an event to a specific webview: import { emitTo } from '@tauri-apps/api/event'; emitTo('settings', 'settings-update-requested', { key: 'notification', value: 'all' });

Global events deliver to all listeners

Global events emitted via emit() are delivered to all listeners registered for that event name.

Event system use cases and limitations

The Tauri event system is designed for small amounts of data that need to be streamed or for implementing a multi-consumer multi-producer pattern like push notifications. It is not designed for low latency or high throughput situations. Use channels instead for streaming data that requires optimization.

Event system differences from commands

Tauri events have no strong type support, event payloads are always JSON strings making them unsuitable for larger messages, and there is no support for the capabilities system to fine-grain control event data and channels.

Event system implementation traits

The AppHandle and WebviewWindow types implement the event system traits Listener and Emitter.

Global events delivery scope

Global events emitted using Emitter#emit are delivered to all listeners regardless of which webview they are registered in.

Webview-specific events with emit_to

Use Emitter#emit_to to trigger an event to a listener registered by a specific webview, targeting that webview by its label.

Webview-specific events with emit_filter

Use Emitter#emit_filter to trigger an event to multiple specific webviews by providing a closure that matches against EventTarget to determine which webviews should receive the event.

Webview-specific events do not trigger global listeners

Webview-specific events emitted with emit_to or emit_filter are not triggered to regular global event listeners. To listen to any event regardless of scope, use the listen_any function instead of listen, which creates a catch-all listener for all emitted events.

Event payload requirements

Event payloads can be any serializable type that also implements Clone. The payload is serialized to JSON for transmission to the frontend.

Global event emission example

Example of using Emitter#emit to trigger global events from a command: ```rust use tauri::{AppHandle, Emitter}; #[tauri::command] fn download(app: AppHandle, url: String) { app.emit("download-started", &url).unwrap(); for progress in [1, 15, 50, 80, 100] { app.emit("download-progress", progress).unwrap(); } app.emit("download-finished", &url).unwrap(); } ```

Webview-specific event emission example

Example of using Emitter#emit_to to trigger an event to a specific webview: ```rust use tauri::{AppHandle, Emitter}; #tauri::command] fn login(app: AppHandle, user: String, password: String) { let authenticated = user == "tauri-apps" && password == "tauri"; let result = if authenticated { "loggedIn" } else { "invalidCredentials" }; app.emit_to("login", "login-result", result).unwrap(); } ```

Emit filter example with multiple webviews

Example of using Emitter#emit_filter to emit an event to multiple specific webviews: ```rust use tauri::{AppHandle, Emitter, EventTarget}; #[tauri::command] fn open_file(app: AppHandle, path: std::path::PathBuf) { app.emit_filter("open-file", path, |target| match target { EventTarget::WebviewWindow { label } => label == "main" || label == "file-viewer", _ => false, }).unwrap(); } ```

Complex event payload with structured types

Example using structured serializable types for event payloads: ```rust use tauri::{AppHandle, Emitter}; use serde::Serialize; #[derive(Clone, Serialize)] #[serde(rename_all = "camelCase")] struct DownloadStarted<'a> { url: &'a str, download_id: usize, content_length: usize, } #[derive(Clone, Serialize)] #[serde(rename_all = "camelCase")] struct DownloadProgress { download_id: usize, chunk_length: usize, } #[derive(Clone, Serialize)] #[serde(rename_all = "camelCase")] struct DownloadFinished { download_id: usize, } #[tauri::command] fn download(app: AppHandle, url: String) { let content_length = 1000; let download_id = 1; app.emit("download-started", DownloadStarted { url: &url, download_id, content_length }).unwrap(); for chunk_length in [15, 150, 35, 500, 300] { app.emit("download-progress", DownloadProgress { download_id, chunk_length, }).unwrap(); } app.emit("download-finished", DownloadFinished { download_id }).unwrap(); } ```

Event system for frontend-Rust communication

The event system is a simpler, less formal communication mechanism than commands. Events are not type-safe, always asynchronous, cannot return values, and only support JSON payloads.

Global events emit to all listeners

Global events are triggered using event.emit() or WebviewWindow#emit() and are delivered to all listeners. Example: emit('file-selected', '/path/to/file'); or getCurrentWebviewWindow().emit('route-changed', { url: window.location.href });

Webview-specific events with emitTo

Webview-specific events target listeners registered on a particular webview using event.emitTo() or WebviewWindow#emitTo(). Example: emitTo('settings', 'settings-update-requested', { key: 'notification', value: 'all' });. Webview-specific events do not trigger on regular global event listeners.

Catch all events with target kind Any

To listen to all events including webview-specific ones, use event.listen with { target: { kind: 'Any' } } option. This makes the listener act as a catch-all. Example: listen('state-changed', (event) => console.log('got state changed event', event), { target: { kind: 'Any' } });

Tauri v2: event system redesign

Event system redesigned: emit now sends to all event listeners; new emit_to function sends to specific targets; emit_filter now filters by EventTarget instead of window; listen_global renamed to listen_any and listens for all events regardless of filter or target.

Give your agent this brain