# Calling State and Lifecycle

The `call` instance manages all call-related functionality: joining, actions (mute, reactions), and event subscriptions. Create instances via `client.call(type, id)`. The `StreamVideoClient` maintains the WebSocket connection and handles API calls.

## Best Practices

- Create call instances only in effects with `call.leave()` cleanup to prevent memory leaks.
- Handle all `CallingState` values exhaustively to show appropriate UI for each state.
- Use `useCallCallingState()` hook for reactive state updates in React components.
- Reuse call instances or create new ones with `client.call(type, id)` to rejoin.

Call instance lifecycle:

```ts
import { Call, StreamVideoClient } from "@stream-io/video-react-sdk";

let client: StreamVideoClient; // ...

const call: Call = client.call(type, id);

// load existing call information from our servers
await call.get();

// Creates the call on our servers in case it doesn't exist. Otherwise,
// loads the call information from our servers.
await call.getOrCreate();

// join the call
await call.join();

// leave the call and dispose all allocated resources
await call.leave();
```

Access calling state via:

- `call.state.callingState` - current value
- `call.state.callingState$` - observable for changes
- `useCallCallingState()` - React hook

## Call Instance

Acquire with `client.call()`, dispose with `call.leave()`. Always create in effects with cleanup:

```ts
const [call, setCall] = useState<Call | undefined>(undefined);

useEffect(() => {
  const myCall = client.call(callType, callId);
  myCall.join({ create: true }).then(
    () => setCall(myCall),
    () => console.error("Failed to join the call"),
  );

  return () => {
    myCall.leave().catch(() => console.error("Failed to leave the call"));
    setCall(undefined);
  };
}, [callType, callId]);
```

To rejoin, reuse the instance or create a new one with `client.call(type, id)`.

## Calling State

The `CallingState` enum exposes call state:

```ts
import { CallingState, useCallStateHooks } from "@stream-io/video-react-sdk";

const { useCallCallingState } = useCallStateHooks();
const callingState = useCallCallingState();

switch (callingState) {
  case CallingState.JOINED:
    // ...
    break;
  default:
    const exhaustiveCheck: never = callingState;
    throw new Error(`Unknown calling state: ${exhaustiveCheck}`);
}
```

>
> **Note:** Handle `CallingState` exhaustively - TypeScript will warn if new states are added.
>

### Calling States

| State                              | Description                                                                                                                                                                      |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CallingState.UNKNOWN`             | The state is unknown. This value is set when Calling State isn't initialized properly.                                                                                           |
| `CallingState.IDLE`                | A call instance is created on the client side but a WebRTC session isn't established yet.                                                                                        |
| `CallingState.RINGING`             | This is an incoming (ring) call. You are the callee.                                                                                                                             |
| `CallingState.JOINING`             | The call join flow is executing (typically right after `call.join()`). Our systems are preparing to accept the new call participant.                                             |
| `CallingState.JOINED`              | The join flow has finished successfully and the current participant is part of the call. The participant can receive and publish audio and video.                                |
| `CallingState.LEFT`                | The call has been left (`call.leave()`) and all allocated resources are released. Please create a new `call` instance if you want to re-join.                                    |
| `CallingState.RECONNECTING`        | A network connection has been lost (due to various factors) and the `call` instance attempts to re-establish a connection and resume the call.                                   |
| `CallingState.RECONNECTING_FAILED` | The SDK failed to recover the connection after a couple of consecutive attempts. You need to inform the user that he needs to go online and manually attempt to rejoin the call. |
| `CallingState.MIGRATING`           | The SFU node that is hosting the current participant is shutting down or tries to rebalance the load. This `call` instance is being migrated to another SFU node.                |
| `CallingState.OFFLINE`             | No network connection can be detected. Once the connection restores, the SDK will automatically attempt to recover the connection (signalled with `RECONNECTING` state).         |

### Calling State transitions: regular path

State transitions when joining a call as caller or callee:

```mermaid
stateDiagram-v2
  direction LR
  [*] --> IDLE
  IDLE --> RINGING: call.join({ ring })
  RINGING --> JOINING
  IDLE --> JOINING: call.join()
  JOINING --> JOINED
  JOINED --> LEFT: call.leave()
  LEFT --> [*]
```

### Calling State transitions: reconnects and migration

State transitions after network interruptions or during SFU node shutdown/rebalancing:

```mermaid
stateDiagram-v2
  direction LR
  [*] --> JOINING
  JOINING --> JOINED: successful join

  JOINED --> RECONNECTING: network glitch/switch
  RECONNECTING --> JOINING: attempt to reconnect
  RECONNECTING --> RECONNECTING_FAILED

  JOINED --> LEFT: call.leave()
  LEFT --> [*]

  JOINED --> MIGRATING: initiate server migration
  MIGRATING --> JOINING: attempt to migrate

  JOINED --> OFFLINE: went offline
  OFFLINE --> RECONNECTING
```

### Example handling

```tsx
import {
  CallingState,
  useCall,
  useCallStateHooks,
} from "@stream-io/video-react-sdk";

const call = useCall();
const isCallCreatedByMe = call?.isCreatedByMe;

const { useCallCallingState } = useCallStateHooks();
const callingState = useCallCallingState();

switch (callingState) {
  case CallingState.UNKNOWN:
  case CallingState.IDLE:
    return <LobbyScreen />;

  case CallingState.RINGING:
    return isCallCreatedByMe ? <OutgoingCallScreen /> : <IncomingCallScreen />;

  case CallingState.JOINING:
    return <LoadingCallScreen />;

  case CallingState.JOINED:
    return <ActiveCallScreen />;

  case CallingState.LEFT:
    return <HaveANiceDayScreen />;

  case CallingState.RECONNECTING:
  case CallingState.MIGRATING:
    return <RestoringConnectionScreen />;

  case CallingState.RECONNECTING_FAILED:
    return <GeneralConnectionErrorScreen />;

  case CallingState.OFFLINE:
    return <NoConnectionScreen />;

  default:
    const exhaustiveCheck: never = callingState;
    throw new Error(`Unknown calling state: ${exhaustiveCheck}`);
}
```

---

For the most recent version of this documentation, visit [https://getstream.io/video/docs/react/v2/guides/calling-state-and-lifecycle/](https://getstream.io/video/docs/react/v2/guides/calling-state-and-lifecycle/).