# @lia-labs/sdk-react

> React hooks for the Lia SDK. Init, Lia's state as hooks, and Lia's buttons shown while a component is mounted. From the Lia developer docs: https://docs.lialabs.org/packages/react

```sh
npm install @lia-labs/sdk @lia-labs/sdk-react
```

React 18 or 19. Everything from [`@lia-labs/sdk`](/packages/sdk) is re-exported, so import it all from here.

## An app

```tsx
import { useEffect, useState } from 'react';
import { isLia, mockLia, pay, ready, useBackButton, useClosingConfirmation, useInit, useLanguage, useMainButton } from '@lia-labs/sdk-react';

if (!isLia()) mockLia(); // building in a desktop browser

export function App() {
  const lia = useInit();
  const language = useLanguage();
  const [screen, setScreen] = useState<'home' | 'game'>('home');

  useEffect(() => {
    if (lia.status === 'ready') ready();
  }, [lia.status]);

  useMainButton(screen === 'home' && { text: 'Buy extra lives', onClick: () => pay('extra-lives') });
  useBackButton(screen === 'game' && (() => setScreen('home')));
  useClosingConfirmation(screen === 'game');

  if (lia.status === 'loading') return null;
  if (lia.status === 'error') return <p>Open this app inside Lia.</p>;
  return <h1>Hello, @{lia.result.player.name} ({language})</h1>;
}
```

## Hooks

| Hook | Gives you |
| --- | --- |
| `useInit(options?)` | `{ status: "loading" | "ready" | "error", result, error }`. Calls `init()` once. |
| `useSignal(value)` | Any SDK value as state (built on `useSyncExternalStore`). |
| `usePlayer()`, `useMode()` | The player, and test or live. |
| `useLanguage()`, `useRtl()` | The person's language. |
| `useColorScheme()`, `useThemeParams()` | Light or dark, and Lia's colours. |
| `useViewport()`, `useSafeArea()`, `useContentSafeArea()`, `useIsFullscreen()` | Layout. |
| `useStartParam()`, `useSoundOn()`, `useNotificationsAllowed()` | The rest of Lia's state. |
| `useLiaEvent(event, handler)` | Listens to one of Lia's events while mounted (always calls your latest handler). |
| `useMainButton(options)`, `useSecondaryButton(options)` | Shows the button while mounted. `options` is `{ text, onClick, isActive, isProgressVisible, color, textColor, position }`; pass `null` or `false` to hide it. Your latest `onClick` is always used. |
| `useBackButton(onBack)` | Shows the header's back button while mounted; `null` or `false` hides it. |
| `useSettingsButton(onOpen)` | Settings in the ⋯ menu while mounted. |
| `useClosingConfirmation(enabled?)` | Asks before closing while enabled. |
| `useVerticalSwipesDisabled(disabled?)` | A swipe down won't close the sheet while disabled. |

## Busy states

```tsx
const [busy, setBusy] = useState(false);
useMainButton({
  text: 'Buy',
  isProgressVisible: busy,
  onClick: async () => {
    setBusy(true);
    try { await buy(); } finally { setBusy(false); }
  },
});
```

## Server rendering

The hooks read their first value straight from the SDK, so they render on a server too (with defaults: English, light, not initialized). `init()` only runs in the browser, in an effect.
