# How iloader Manages Stateful Objects Like Selected Devices: React State and Tauri Bridge Pattern

> Discover how iloader manages stateful objects like selected devices using React state and the Tauri bridge pattern, ensuring a single source of truth between UI and backend.

- Repository: [Nicholas Sharp/iloader](https://github.com/nab138/iloader)
- Tags: deep-dive
- Published: 2026-09-13

---

**iloader manages the selected device as a local React state variable in the root App component, synchronizing it with the Tauri backend via the `set_selected_device` invoke command to maintain a single source of truth across both the UI and native layers.**

The [nab138/iloader](https://github.com/nab138/iloader) repository implements a cross-platform desktop application for managing iOS devices using a React frontend and Tauri backend. Understanding how iloader manages stateful objects like selected devices reveals a hybrid architecture where JavaScript state drives the interface while Rust handles hardware persistence. The pattern ensures that UI selections immediately propagate to the native layer for certificate handling, pairing, and installation operations.

## React State as the Single Source of Truth

The application treats the **selected device** as a nullable object stored in the top-level component, making it available to the entire component tree through prop drilling.

### Root State Declaration in App.tsx

The canonical state definition lives at line 38 of the main application file, where [`App.tsx`](https://github.com/nab138/iloader/blob/main/App.tsx) initializes the device selection as `null` until the user makes a choice:

```tsx
// src/App.tsx
const [selectedDevice, setSelectedDevice] = useState<DeviceInfo | null>(null);

```

[View in source](https://github.com/nab138/iloader/blob/main/src/App.tsx#L38)

This `useState` hook returns a tuple containing the current device object and its setter. The `DeviceInfo` type presumably contains device identifiers, names, and connection state. By declaring this state at the root, iloader ensures that any component receiving `selectedDevice` props always references the same memory instance.

### Prop Distribution to Child Components

The `selectedDevice` state and its updater function flow down to child components via explicit props rather than context providers. The `<Device>` component receives both values to render the device list and handle selection events:

```tsx
<Device
  selectedDevice={selectedDevice}
  setSelectedDevice={setSelectedDevice}
/>

```

This explicit prop passing makes data dependencies traceable and prevents accidental state staleness in deep component trees.

## Synchronizing with the Tauri Backend

State changes in React must propagate to the Rust backend so that native operations target the correct hardware. iloader implements this through Tauri's **invoke command bridge**.

### Invoking set_selected_device from Device.tsx

When a user clicks a device card in the UI, the component calls a local `selectDevice` handler that performs dual updates: it notifies the Rust layer first, then updates React state only after the native promise resolves. This pattern prevents UI desynchronization if the backend rejects the selection:

```tsx
// src/Device.tsx – lines 66-75
const selectDevice = (device: DeviceInfo | null) => {
  invoke("set_selected_device", { device })
    .then(() => {
      setSelectedDevice(device);
    })
    .catch((err) => {
      console.error("Failed to select device", err);
    });
};

```

[View in source](https://github.com/nab138/iloader/blob/main/src/Device.tsx#L66-L75)

The `invoke` function serializes the `DeviceInfo` payload and sends it across the Tauri IPC bridge to the Rust runtime.

### Command Registration in the Rust Layer

The backend exposes the `set_selected_device` command through Tauri's command macro system. In the library entry point, the command is registered at line 21:

```rust
// src-tauri/src/lib.rs
fn run() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![
            // ... other commands
            set_selected_device,
        ])
        .run(...)
}

```

[View in source](https://github.com/nab138/iloader/blob/main/src-tauri/src/lib.rs#L21)

The actual implementation resides in [`device.rs`](https://github.com/nab138/iloader/blob/main/device.rs) beginning around line 124, where the Rust function receives the serialized device data and updates the native state manager responsible for USB/lockdown communication:

```rust
// src-tauri/src/device.rs
#[tauri::command]
pub async fn set_selected_device(state: State<'_, DeviceState>, device: Option<DeviceInfo>) -> Result<(), String> {
    // Native device handle acquisition and validation
    state.select_device(device).await
}

```

[View implementation](https://github.com/nab138/iloader/blob/main/src-tauri/src/device.rs#L124)

### Cross-Component Consistency Patterns

Other pages like Settings also invoke the same command to ensure the backend remains synchronized when implicit selection changes occur. At line 186 of the settings page, the code calls the command directly without updating React state, assuming the UI layer has already handled the visual update:

```tsx
// src/pages/Settings.tsx
await invoke("set_selected_device");

```

[View in source](https://github.com/nab138/iloader/blob/main/src/pages/Settings.tsx#L186)

## Validation and Error Handling

Operating on a null device causes runtime errors in the native layer. iloader implements defensive programming through a validation callback that guards all device-dependent operations.

### The ensureSelectedDevice Guard

Defined at lines 46-50 in [`App.tsx`](https://github.com/nab138/iloader/blob/main/App.tsx), this `useCallback` hook returns a boolean indicating whether a device is currently selected, displaying a toast notification if not:

```tsx
// src/App.tsx
const ensureSelectedDevice = useCallback((): boolean => {
  if (selectedDevice) return true;
  toast.error(t("app.must_select_device"));
  return false;
}, [selectedDevice, t]);

```

[View in source](https://github.com/nab138/iloader/blob/main/src/App.tsx#L46-L50)

Operations such as installing applications or modifying system settings call this guard before proceeding:

```tsx
if (!ensureSelectedDevice()) return;
startOperation(installSideStoreOperation, { nightly: false });

```

### Automatic Cleanup on Disconnect

The Device component implements a reconciliation effect that validates whether the `selectedDevice` still exists in the refreshed device list. If the previously selected hardware disconnects, the component automatically invokes `selectDevice(null)` to clear the stale reference, preventing operations against disconnected devices.

## Key Implementation Files and Functions

| File | Responsibility | Key Lines |
|------|----------------|-----------|
| [src/App.tsx](https://github.com/nab138/iloader/blob/main/src/App.tsx) | React state declaration and validation guards | [L38](https://github.com/nab138/iloader/blob/main/src/App.tsx#L38), [L46-L50](https://github.com/nab138/iloader/blob/main/src/App.tsx#L46-L50) |
| [src/Device.tsx](https://github.com/nab138/iloader/blob/main/src/Device.tsx) | UI rendering and selection event handling | [L66-L75](https://github.com/nab138/iloader/blob/main/src/Device.tsx#L66-L75) |
| [src/pages/Settings.tsx](https://github.com/nab138/iloader/blob/main/src/pages/Settings.tsx) | Secondary invocations for backend sync | [L186](https://github.com/nab138/iloader/blob/main/src/pages/Settings.tsx#L186) |
| [src-tauri/src/lib.rs](https://github.com/nab138/iloader/blob/main/src-tauri/src/lib.rs) | Tauri command registration | [L21](https://github.com/nab138/iloader/blob/main/src-tauri/src/lib.rs#L21) |
| [src-tauri/src/device.rs](https://github.com/nab138/iloader/blob/main/src-tauri/src/device.rs) | Native device state implementation | [L124+](https://github.com/nab138/iloader/blob/main/src-tauri/src/device.rs#L124) |

## Summary

- **Single React state**: The root [`App.tsx`](https://github.com/nab138/iloader/blob/main/App.tsx) component owns the `selectedDevice` state, making it the single source of truth for the entire UI.
- **Tauri bridge synchronization**: Selection changes propagate to the Rust backend via the `set_selected_device` invoke command, ensuring hardware operations target the correct device.
- **Promise-based updates**: The UI updates only after the backend successfully processes the selection, preventing state desynchronization.
- **Validation guards**: The `ensureSelectedDevice` callback prevents operations when no device is selected, providing user feedback through toast notifications.
- **Automatic stale data cleanup**: The device list component clears the selection if the active device disconnects, maintaining state integrity.

## Frequently Asked Questions

### Where is the selected device state stored in iloader?

The selected device state resides in the root [`App.tsx`](https://github.com/nab138/iloader/blob/main/App.tsx) component as a standard React `useState` variable initialized to `null`. This state is passed down to child components via props, specifically to the `Device` component which handles the visual selection interface.

### How does iloader persist the selected device across sessions?

Based on the source analysis, iloader does **not** persist the selected device across application sessions. The state initializes as `null` on every app launch, requiring the user to reselect their device. The `set_selected_device` command only maintains state during the current runtime within the Tauri backend's memory.

### What happens if the selected device disconnects while iloader is running?

The `Device` component includes reconciliation logic that checks whether the `selectedDevice` exists in the current device list after each refresh. If the selected device disappears from the available hardware list, the component automatically calls `selectDevice(null)` to clear the selection and prevent operations against a disconnected device.

### How can I check if a device is selected before running an operation?

Use the `ensureSelectedDevice` callback provided by the [`App.tsx`](https://github.com/nab138/iloader/blob/main/App.tsx) component. This function returns `true` if a device is selected, or `false` if `selectedDevice` is `null`, simultaneously displaying an error toast to notify the user. Guard your operation handlers with this check before invoking Tauri commands that require device connectivity.