---
title: "Hooks and Call State | Micdrop"
description: "Read the Micdrop call state from a React Native screen with the same hooks a web app uses."
url: "https://micdrop.dev/docs/react-native/hooks"
---

# Hooks and Call State

The hooks live in `@micdrop/react` and are the same ones a web app uses, since the call state comes from `@micdrop/client` on both platforms.

```bash
npm install @micdrop/react
```

Only the components around them change, `Text` and `View` instead of `div`:

```tsx
import { useMicdropState } from '@micdrop/react'
import { Text } from 'react-native'

function CallStatus() {
  const state = useMicdropState()

  if (state.isReconnecting) return <Text>Reconnecting</Text>
  if (state.isStarting) return <Text>Starting</Text>
  if (!state.isStarted) return <Text>Ready</Text>
  if (state.isUserSpeaking) return <Text>Listening</Text>
  if (state.isAssistantSpeaking) return <Text>Speaking</Text>
  if (state.isProcessing) return <Text>Thinking</Text>
  return <Text>Your turn</Text>
}
```

Every hook and every field of the state is documented once, for both platforms:

*   [React hooks](/docs/client/react-hooks) for `useMicdropState`, `useMicdropError`, `useMicdropEndCall`, `useMicdropToolCall`, `useMicdropClassification`, `useMicVolume` and `useSpeakerVolume`
*   [Call state](/docs/client/call-state) for what each field means and how the states follow one another
*   [Error handling](/docs/client/error-handling) for the error codes, which are the same when the microphone is refused or the server is unreachable

## What a phone reads differently

`state.speakerDeviceId` is a route rather than a device, `'speaker'` or `'earpiece'`, see [Audio output and devices](/docs/react-native/audio-output). `state.micDevices` fills up once the call has started, since the audio session has to be active for the system to answer.

## Leaving the screen when the assistant hangs up

`useMicdropEndCall` fires when the agent ends the call on its own, see [Auto end call](/docs/server/auto-end-call). On a phone that usually means stopping the call and going back:

```tsx
import { useMicdropEndCall } from '@micdrop/react'
import { Micdrop } from '@micdrop/react-native'
import { useCallback } from 'react'

function CallScreen() {
  useMicdropEndCall(
    useCallback(() => {
      Micdrop.stop()
      navigation.goBack()
    }, [navigation])
  )
}
```

Wrap the callback in `useCallback`, the hook resubscribes whenever it changes.

## Level meters

`useMicVolume` and `useSpeakerVolume` give levels in decibels, updated about ten times a second, for a meter or a pulsing avatar. Silence reads as `-Infinity`, so map the range you care about:

```tsx
import { useMicVolume } from '@micdrop/react'
import { View } from 'react-native'

function MicMeter() {
  const { micVolume } = useMicVolume()
  const ratio = Math.max(0, Math.min(1, (micVolume + 60) / 60))

  return <View style={{ width: `${ratio * 100}%`, height: 8 }} />
}
```
