> ## Documentation Index
> Fetch the complete documentation index at: https://docs.daily.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Thinking in Daily React

> The reactive mental model behind Daily React: hooks as selectors, granular re-renders, and events as subscriptions.

Daily React is small once the mental model clicks. This page is the model. The rest of the guides are applications of it.

## From listeners to hooks

With plain `daily-js`, a call is a stream of events. You keep your own copy of call state and update it as events arrive:

```js theme={null}
// daily-js: you own the state and the listeners
const participants = {};

call
  .on('participant-joined', (e) => {
    participants[e.participant.session_id] = e.participant;
    render();
  })
  .on('participant-updated', (e) => {
    participants[e.participant.session_id] = e.participant;
    render();
  })
  .on('participant-left', (e) => {
    delete participants[e.participant.session_id];
    render();
  });
```

Daily React keeps that state for you in an internal store and exposes it through hooks. The same logic becomes:

```jsx theme={null}
// Daily React: read the state, let it re-render you
import { useParticipantIds } from '@daily-co/daily-react';

function CallGrid() {
  const participantIds = useParticipantIds();
  return participantIds.map((id) => <Tile key={id} sessionId={id} />);
}
```

There are no listeners to register and none to tear down. When a participant joins or leaves, the store updates and any component reading `useParticipantIds` re-renders.

## Hooks are selectors

Under the hood, Daily React stores call state in [Jotai](https://jotai.org/) atoms and updates them as `daily-js` events fire. Each hook is a **selector**: it reads one slice of that store and subscribes your component to changes in that slice only.

This is the single most important thing to internalize, because it drives both correctness and performance. Two hooks that read different slices re-render independently:

* [`useParticipantIds`](/reference/daily-react/use-participant-ids) re-renders when the set of participants changes, not when one participant mutes.
* [`useParticipantProperty(id, 'user_name')`](/reference/daily-react/use-participant-property) re-renders when that one participant's name changes, and ignores everything else.

### Read the smallest slice you need

Prefer the narrow hook over the broad one. Reading a whole participant object re-renders your component on every property change; reading a single property does not.

```jsx theme={null}
// Re-renders only when this participant's audio subscription changes:
const isAudioSubscribed = useParticipantProperty(
  sessionId,
  'tracks.audio.subscribed'
);
```

The same principle is why dedicated hooks exist for common slices:

| Want                     | Use                                                                         | Not                                |
| ------------------------ | --------------------------------------------------------------------------- | ---------------------------------- |
| The local session ID     | [`useLocalSessionId`](/reference/daily-react/use-local-session-id)          | the full local participant object  |
| One participant property | [`useParticipantProperty`](/reference/daily-react/use-participant-property) | the full participant object        |
| Who is speaking          | [`useActiveSpeakerId`](/reference/daily-react/use-active-speaker-id)        | the full active participant object |

<Note>
  The object-returning hooks `useParticipant`, `useLocalParticipant`, and `useActiveParticipant` are **deprecated as of 0.17.0** in favor of the property-and-ID hooks above, precisely because returning whole objects causes broad re-renders. New code should use the narrow hooks.
</Note>

## Events become hook callbacks

You rarely call [`useDailyEvent`](/reference/daily-react/use-daily-event) directly, because most events already have a hook that exposes their state and an optional callback. Reach for the feature hook first:

| Instead of listening for         | Use                                                                                                       |
| -------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `participant-joined` / `-left`   | [`useParticipantIds`](/reference/daily-react/use-participant-ids) (or its `onParticipantJoined` callback) |
| `active-speaker-change`          | [`useActiveSpeakerId`](/reference/daily-react/use-active-speaker-id)                                      |
| `recording-started` / `-stopped` | [`useRecording`](/reference/daily-react/use-recording)                                                    |
| `transcription-message`          | [`useTranscription`](/reference/daily-react/use-transcription)                                            |
| `app-message`                    | [`useAppMessage`](/reference/daily-react/use-app-message)                                                 |
| `network-quality-change`         | [`useNetwork`](/reference/daily-react/use-network)                                                        |

Drop down to [`useDailyEvent`](/reference/daily-react/use-daily-event) only for events without a dedicated hook. See [Handling events](/docs/daily-react/docs/events) for the rules.

## Components own the DOM

Hooks give you state; two things in a call need to touch the DOM directly, and those are components:

* [`DailyVideo`](/reference/daily-react/daily-video) attaches a participant's video track to a `<video>` element.
* [`DailyAudio`](/reference/daily-react/daily-audio) plays remote audio, managing speaker slots and autoplay.

Keeping media in components means your render logic stays declarative: you map participant IDs to `<DailyVideo>` elements and never imperatively call `el.srcObject = ...`. See [Rendering media](/docs/daily-react/docs/rendering-media).

## The escape hatch

Daily React does not wrap every `daily-js` method. When you need one that has no dedicated hook, get the call object with [`useDaily`](/reference/daily-react/use-daily) and call it directly:

```jsx theme={null}
import { useDaily } from '@daily-co/daily-react';

function MuteButton({ sessionId }) {
  const daily = useDaily();
  return (
    <button onClick={() => daily.updateParticipant(sessionId, { setAudio: false })}>
      Mute
    </button>
  );
}
```

`useDaily` returns the exact same [`DailyCall`](/reference/daily-js/daily-call-client) instance you would get from `daily-js`, so anything in the daily-js reference works here. The difference is that imperative calls do not re-render anything by themselves; the resulting events flow back through the store and re-render the hooks that read the affected state.

## Putting it together

A Daily React component, in one breath: **read the state you need with the narrowest hooks, render media with components, and use `useDaily` for the imperative actions that have no hook.** Everything else, the subscriptions and the cleanup, is handled for you.

## Next steps

<CardGroup cols={2}>
  <Card title="The call object and provider" icon="box" href="/docs/daily-react/docs/call-object-and-provider">
    Creating, joining, and leaving.
  </Card>

  <Card title="Working with participants" icon="users" href="/docs/daily-react/docs/participants">
    The hooks that read participant state.
  </Card>

  <Card title="Handling events" icon="bolt" href="/docs/daily-react/docs/events">
    When and how to use the event hooks.
  </Card>

  <Card title="Rendering media" icon="video" href="/docs/daily-react/docs/rendering-media">
    Video and audio components.
  </Card>
</CardGroup>
