<!-- AvatarFactory Docs · https://avatarfactory.in/docs/sdk/react-native/use-avatar-event · Full map: https://avatarfactory.in/llms.txt -->

# useAvatarEvent

Subscribe to avatar lifecycle events with automatic cleanup — no useEffect, no manual off() calls.

## Usage

```tsx
import { useAvatarEvent } from "@avatarfactory/react-native";

function MyScreen() {
  useAvatarEvent("start", () => {
    console.log("Session connected");
  });

  useAvatarEvent("error", (error) => {
    console.error(`[${error.code}] ${error.message}`);
  });

  useAvatarEvent("speaking", () => {
    console.log("Avatar is talking");
  });

  return null;
}
```

Must be used within ``.

## Signature

```tsx
function useAvatarEvent<E extends keyof AvatarEventMap>(
  event: E,
  handler: AvatarEventMap[E],
): void;
```

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `event` **(required)** | `keyof AvatarEventMap` | — | The event name to subscribe to. |
| `handler` **(required)** | `Function` | — | The callback invoked when the event fires. Typed per event. |

## Available events

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `start` | `() => void` | — | Session connected and started successfully. |
| `stop` | `() => void` | — | Session disconnected — either by calling stop() or a network drop. |
| `speaking` | `() => void` | — | Avatar began speaking. |
| `interrupt` | `() => void` | — | Avatar speech was cut short by interrupt(). |
| `ready` | `() => void` | — | Avatar has rendered on screen and is visually ready. |
| `error` | `(error: AvatarError) => void` | — | An error occurred. Check error.fatal to decide how to respond. |
| `notice` | `(notice: SessionNotice) => void` | — | A graceful, server-initiated message (plan limit, demo cap, expiring test key). The avatar speaks it and the session then closes — not an error. |
| `transcript` | `(entries: TranscriptEntry[]) => void` | — | The whole transcript, re-emitted on every change. Only fires when transcript.enabled is set. |
| `health` | `(health: ConnectionHealth) => void` | — | Connection health, re-emitted whenever the server reports stream health. |

> The handler is re-read on every render, so you can close over current props and
>   state without re-subscribing.

## useAvatarEvent vs on/off

          Feature
          useAvatarEvent
          on / off

          Auto-cleanup on unmount
          Yes
          No — you must call off()

          Multiple events per call
          One hook per event
          Yes — group in one useEffect

          Use outside React lifecycle
          No
          Yes

> **Default to `useAvatarEvent`** — simpler and prevents memory leaks. Reach for `on`/`off` only when you need to subscribe outside the React component lifecycle.

## Examples

### Analytics tracking

```tsx
function AnalyticsTracker() {
  useAvatarEvent("start", () => analytics.track("avatar_session_started"));

  useAvatarEvent("error", (error) => {
    analytics.track("avatar_error", {
      code: error.code,
      source: error.source,
      fatal: error.fatal,
      message: error.message,
    });
  });

  return null; // Pure side-effect component — renders nothing
}
```

### Speaking indicator

```tsx
import { Text } from "react-native";

function SpeakingIndicator() {
  const [isTalking, setIsTalking] = useState(false);

  useAvatarEvent("speaking", () => setIsTalking(true));
  useAvatarEvent("stop", () => setIsTalking(false));
  useAvatarEvent("interrupt", () => setIsTalking(false));

  return isTalking
    ? <Text style={{ color: "#22c55e" }}>Speaking…</Text>
    : null;
}
```

### Full event logger

```tsx
function EventLogger() {
  useAvatarEvent("start",     () => console.log("[avatar] started"));
  useAvatarEvent("stop",      () => console.log("[avatar] stopped"));
  useAvatarEvent("speaking",  () => console.log("[avatar] speaking"));
  useAvatarEvent("ready",     () => console.log("[avatar] ready"));
  useAvatarEvent("interrupt", () => console.log("[avatar] interrupted"));
  useAvatarEvent("error",     (e) => console.error("[avatar] error:", e.code));

  return null;
}
```
