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

# React-хуки

> Provider и реактивные хуки для MiniApp на React

Модуль `@exode-team/sdk/miniapp/react` предоставляет декларативный слой над `ExodeMiniApp` для React-приложений. Все хуки реактивные: при событиях хоста компоненты автоматически перерендериваются.

<Info>
  React — опциональная peer-зависимость. Если в проекте нет React, этот модуль не нужен — используйте [ванильный клиент](/ru/exode-sdk/miniapp/client).
</Info>

## Provider

Оборачивает приложение, создаёт `ExodeMiniApp`, выполняет handshake и распространяет подписки на события:

```jsx theme={null}
import { ExodeMiniAppProvider } from '@exode-team/sdk/miniapp/react'

function App() {
  return (
    <ExodeMiniAppProvider config={{ appId: 'my-app' }}>
      <MyApp />
    </ExodeMiniAppProvider>
  )
}
```

### Параметры

<ResponseField name="config" type="ExodeMiniAppProviderConfig" required>
  Конфигурация клиента: `appId`, `targetOrigin?`, `timeout?` плюс `renderMode?`.

  <Expandable title="renderMode">
    Режим рендеринга детей:

    * `'defer'` (по умолчанию) — дети монтируются только после handshake (обратная совместимость).
    * `'immediate'` — дети монтируются с первого рендера (в т.ч. при SSR); до готовности хуки возвращают
      значения по умолчанию (`scheme: 'light'`, `user: null` и т.п.).
  </Expandable>
</ResponseField>

## useExodeApp

Состояние подключения и низкоуровневый доступ к инстансу `ExodeMiniApp`.

```jsx theme={null}
function Status() {
  const { app, isReady, error } = useExodeApp()

  if (error) return <div>Ошибка подключения: {error.message}</div>
  if (!isReady) return <div>Соединение с Exode...</div>

  return <div>Подключено</div>
}
```

| Поле      | Тип                    | Описание                                    |
| --------- | ---------------------- | ------------------------------------------- |
| `app`     | `ExodeMiniApp \| null` | Экземпляр клиента (или `null` до handshake) |
| `isReady` | `boolean`              | Handshake завершён                          |
| `error`   | `Error \| null`        | Ошибка инициализации                        |

## useExodeUser

Текущий пользователь. Обновляется на событии `user:updated`.

```jsx theme={null}
function Greeting() {
  const { user, isLoggedIn } = useExodeUser()

  if (!isLoggedIn) return <div>Не авторизован</div>

  return <div>Привет, {user.firstName}</div>
}
```

## useExodeTheme

Текущая тема. Обновляется на событии `theme:changed`.

```jsx theme={null}
function ThemedBox() {
  const { scheme, isDark } = useExodeTheme()

  return (
    <div style={{ background: isDark ? '#1a1a1a' : '#ffffff' }}>
      Схема: {scheme}
    </div>
  )
}
```

## useExodeSchool

Данные школы. Обновляется на событии `school:updated`.

```jsx theme={null}
function SchoolInfo() {
  const { school } = useExodeSchool()

  return <div>{school?.name as string}</div>
}
```

## useExodeConfig

Конфигурация окружения. Обновляется на событии `config:updated`.

```jsx theme={null}
function Layout({ children }) {
  const { isDesktop, isMobile, language, platform } = useExodeConfig()

  return (
    <div className={isMobile ? 'layout-compact' : 'layout-wide'} lang={language}>
      {children}
    </div>
  )
}
```

## useExodeNavigation

Команды навигации основного приложения.

```jsx theme={null}
function NavButtons() {
  const { navigate, back } = useExodeNavigation()

  return (
    <>
      <button onClick={() => navigate('/course/123', { tab: 'lessons' })}>
        Открыть курс
      </button>
      <button onClick={() => back()}>Назад</button>
    </>
  )
}
```

## useExodeUI

UI-команды к хосту.

```jsx theme={null}
function Controls() {
  const { showSnackbar, setTabbarVisible, setHeaderVisible, close } = useExodeUI()

  return (
    <>
      <button onClick={() => showSnackbar({ message: 'Готово!', type: 'success' })}>
        Уведомление
      </button>
      <button onClick={() => setTabbarVisible(false)}>Скрыть tabbar</button>
      <button onClick={() => close()}>Закрыть приложение</button>
    </>
  )
}
```

## Требования

<Warning>
  Все хуки работают только внутри `<ExodeMiniAppProvider>`. Вызов за его пределами выбросит ошибку.
</Warning>

## Полный пример

```jsx theme={null}
import {
  ExodeMiniAppProvider,
  useExodeApp,
  useExodeUser,
  useExodeTheme,
  useExodeUI,
} from '@exode-team/sdk/miniapp/react'

function Content() {
  const { isReady, error } = useExodeApp()
  const { user } = useExodeUser()
  const { isDark } = useExodeTheme()
  const { showSnackbar } = useExodeUI()

  if (error) return <div>Ошибка: {error.message}</div>
  if (!isReady) return <div>Загрузка...</div>

  return (
    <div data-theme={isDark ? 'dark' : 'light'}>
      <h1>Привет, {user.firstName}</h1>
      <button onClick={() => showSnackbar({ message: 'Привет!', type: 'info' })}>
        Показать уведомление
      </button>
    </div>
  )
}

export default function App() {
  return (
    <ExodeMiniAppProvider config={{ appId: 'my-app' }}>
      <Content />
    </ExodeMiniAppProvider>
  )
}
```
