БлогУслугиКарьера
Обсудить проект
БлогУслугиКарьераОбсудить проект
Mini Apps

Вы пишете Telegram Mini App неправильно. Вот доказательство

Большинство туториалов по @telegram-apps/sdk-react учат неправильно. Разбираем initDataUnsafe, MainButton, BackButton — с кодом и объяснением, что на самом деле происходит.

Редакция Feature
Редакция Feature·
3 апр
·
12 мин
·
Вы пишете Telegram Mini App неправильно. Вот доказательство

Если вы когда-нибудь пытались разобраться с @telegram-apps/sdk-react по официальной документации — вы знаете, как это бывает. Половина примеров устарела, TypeScript ругается на типы, а в чате поддержки советуют «почитать исходники».

Эта статья — то, что хотелось бы иметь при первом знакомстве с SDK. Разбираем всё по порядку: установка, инициализация, работа с UI-компонентами Telegram, получение данных пользователя и типичные ошибки, которые встречаются почти в каждом проекте.

Что такое @telegram-apps/sdk-react и зачем он нужен

Telegram Mini Apps работают через WebApp API — набор методов, которые Telegram встраивает в JavaScript-окружение браузера. Напрямую работать с window.Telegram.WebApp можно, но неудобно: нет типов, нет реактивности, код быстро превращается в кашу.

@telegram-apps/sdk-react — это обёртка над WebApp API с React-хуками, TypeScript-типами и удобными компонентами. Он берёт на себя инициализацию и даёт вам чистый декларативный интерфейс.

Основные возможности:

  • Хуки для работы с MainButton, BackButton, SettingsButton
  • Реактивный доступ к данным пользователя (initDataUnsafe)
  • Управление Viewport и цветовой схемой
  • Работа с CloudStorage
  • Поддержка платежей через Invoice

Установка и настройка проекта

Создаём проект. Рекомендуется Vite + React + TypeScript:

npm create vite@latest my-mini-app -- --template react-ts
cd my-mini-app
npm install

Устанавливаем SDK:

npm install @telegram-apps/sdk-react @telegram-apps/sdk

Для разработки без Telegram-клиента понадобится эмулятор:

npm install -D @telegram-apps/telegram-mock

Структура проекта после установки:

src/
├── components/
├── hooks/
├── App.tsx
├── main.tsx
└── mockEnv.ts   # для разработки

Инициализация SDK

Это первое, что нужно сделать до любого использования хуков. Инициализация должна произойти до монтирования React-дерева.

// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import {init, isTMA} from '@telegram-apps/sdk-react';
import App from './App';

async function bootstrap() {
    // В dev-режиме эмулируем окружение Telegram
    if (import.meta.env.DEV) {
        const {mockTelegramEnv, parseInitData} = await import('@telegram-apps/telegram-mock');

        mockTelegramEnv({
            themeParams: {
                accentTextColor: '#6ab2f2',
                bgColor: '#17212b',
                buttonColor: '#5288c1',
                buttonTextColor: '#ffffff',
                headerBgColor: '#17212b',
                hintColor: '#708499',
                linkColor: '#6ab3f3',
                secondaryBgColor: '#232e3c',
                sectionBgColor: '#17212b',
                sectionHeaderTextColor: '#6ab3f3',
                subtitleTextColor: '#708499',
                textColor: '#f5f5f5',
            },
            initDataRaw: new URLSearchParams([
                ['user', JSON.stringify({
                    id: 123456789,
                    first_name: 'Иван',
                    last_name: 'Петров',
                    username: 'ivan_petrov',
                    language_code: 'ru',
                })],
                ['hash', 'test_hash'],
            ]).toString(),
        });
    }

    // Проверяем, что мы внутри Telegram
    if (isTMA('simple')) {
        await init();
    }

    ReactDOM.createRoot(document.getElementById('root')!).render(
        <React.StrictMode>
            <App/>
        </React.StrictMode>
    );
}

bootstrap();

Важный момент: init() — асинхронная функция. Не вызывайте хуки SDK до её завершения, иначе получите ошибку SDK is not initialized.

SDKProvider — оборачиваем приложение

// src/App.tsx
import {SDKProvider} from '@telegram-apps/sdk-react';
import {MainScreen} from './components/MainScreen';

export default function App() {
    return (
        <SDKProvider acceptCustomStyles debug={import.meta.env.DEV}>
            <MainScreen/>
        </SDKProvider>
    );
}

acceptCustomStyles — позволяет Telegram применять свои CSS-переменные для темизации. Рекомендуется включать всегда.

Получение данных пользователя: initDataUnsafe

Это самый частый вопрос в поиске — initDataUnsafe @telegram-apps/sdk. Разбираем подробно.

import {useInitData} from '@telegram-apps/sdk-react';

function UserProfile() {
    const initData = useInitData();

    if (!initData) {
        return <div>Загрузка...</div>;
    }

    const {user} = initData;

    if (!user) {
        return <div>Пользователь не определён</div>;
    }

    return (
        <div>
            <p>Имя: {user.firstName} {user.lastName}</p>
            <p>Username: @{user.username}</p>
            <p>ID: {user.id}</p>
            <p>Язык: {user.languageCode}</p>
        </div>
    );
}

Почему "Unsafe"? Потому что данные из initDataUnsafe не верифицированы на клиенте. Для продакшена обязательно проверяйте initData.hash на бэкенде:

# Пример верификации на Python (бэкенд)
import hashlib
import hmac

def verify_init_data(init_data: str, bot_token: str) -> bool:
    parsed = dict(item.split('=', 1) for item in init_data.split('&'))
    received_hash = parsed.pop('hash', '')
    
    data_check_string = '\n'.join(
        f'{k}={v}' for k, v in sorted(parsed.items())
    )
    
    secret_key = hmac.new(
        b'WebAppData',
        bot_token.encode(),
        hashlib.sha256
    ).digest()
    
    expected_hash = hmac.new(
        secret_key,
        data_check_string.encode(),
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(received_hash, expected_hash)

Нужна Telegram Mini App?

Разработаем Mini App под ваши задачи — от простого каталога до полноценного магазина

Заказать Mini App

MainButton — кнопка в нижней панели

MainButton — одна из самых используемых фич. Это кнопка, которая появляется в нижней части экрана Telegram.

import {useMainButton} from '@telegram-apps/sdk-react';
import {useEffect} from 'react';

function OrderForm() {
    const mainButton = useMainButton();

    useEffect(() => {
        mainButton.setParams({
            text: 'Оформить заказ',
            isVisible: true,
            isEnabled: true,
            backgroundColor: '#bdfe52',
            textColor: '#000000',
        });

        const handleClick = () => {
            mainButton.showProgress(); // Показываем загрузку
            submitOrder().then(() => {
                mainButton.hideProgress();
                mainButton.setParams({text: '✓ Заказ оформлен', isEnabled: false});
            });
        };

        mainButton.on('click', handleClick);

        return () => {
            mainButton.off('click', handleClick);
            mainButton.hide(); // Скрываем при размонтировании
        };
    }, [mainButton]);

    return (
        <form>
            {/* Поля формы */}
        </form>
    );
}

Типичная ошибка: не скрывать MainButton при размонтировании компонента. Кнопка останется видимой на других экранах.

BackButton — навигация назад

import {useBackButton} from '@telegram-apps/sdk-react';
import {useEffect} from 'react';
import {useNavigate} from 'react-router-dom';

function ProductPage() {
    const backButton = useBackButton();
    const navigate = useNavigate();

    useEffect(() => {
        backButton.show();

        const handleBack = () => navigate(-1);
        backButton.on('click', handleBack);

        return () => {
            backButton.off('click', handleBack);
            backButton.hide();
        };
    }, [backButton, navigate]);

    return <div>{/* Содержимое страницы */}</div>;
}

Совет: выделите логику BackButton в кастомный хук, если используете роутинг:

// hooks/useTelegramBackButton.ts
import {useBackButton} from '@telegram-apps/sdk-react';
import {useEffect} from 'react';
import {useNavigate} from 'react-router-dom';

export function useTelegramBackButton() {
    const backButton = useBackButton();
    const navigate = useNavigate();

    useEffect(() => {
        backButton.show();
        const handleBack = () => navigate(-1);
        backButton.on('click', handleBack);

        return () => {
            backButton.off('click', handleBack);
            backButton.hide();
        };
    }, [backButton, navigate]);
}

Viewport и адаптация к размеру экрана

Mini App запускается во встроенном WebView, размер которого может меняться (например, при открытии клавиатуры). Используйте useViewport чтобы реагировать на изменения:

import {useViewport} from '@telegram-apps/sdk-react';

function ResponsiveLayout() {
    const viewport = useViewport();

    // Расширяем на весь экран при старте
    useEffect(() => {
        viewport?.expand();
    }, [viewport]);

    const height = viewport?.height ?? window.innerHeight;
    const isExpanded = viewport?.isExpanded ?? false;

    return (
        <div style={{height: `${height}px`, overflow: 'hidden'}}>
            {/* Контент */}
        </div>
    );
}

CloudStorage — хранение данных без бэкенда

CloudStorage позволяет хранить небольшие данные (до 1024 байт на ключ, до 1024 ключей) напрямую в Telegram. Удобно для настроек, корзины покупок или черновиков:

import {useCloudStorage} from '@telegram-apps/sdk-react';

function CartStorage() {
    const cloudStorage = useCloudStorage();

    const saveCart = async (items: CartItem[]) => {
        await cloudStorage.set('cart', JSON.stringify(items));
    };

    const loadCart = async (): Promise<CartItem[]> => {
        const data = await cloudStorage.get('cart');
        return data ? JSON.parse(data) : [];
    };

    const clearCart = async () => {
        await cloudStorage.delete('cart');
    };

    return {saveCart, loadCart, clearCart};
}

Ограничение: CloudStorage — не замена базе данных. Данные привязаны к конкретному пользователю и конкретному боту, доступны только при открытой Mini App.

Обсудим ваш проект?

Оставьте контакты — перезвоним и обсудим задачу

Типичные ошибки и как их избежать

За несколько лет разработки Mini Apps мы собрали список ошибок, которые встречаются почти в каждом проекте.

Ошибка 1: Вызов хуков до инициализации

// ❌ Неправильно
function App() {
    const initData = useInitData(); // SDK ещё не инициализирован!
    // ...
}

// ✅ Правильно — дождаться init() в main.tsx до рендера

Ошибка 2: Не проверять наличие данных

// ❌ Упадёт если user === undefined
const {user} = useInitData()!;
console.log(user.firstName);

// ✅
const initData = useInitData();
if (!initData?.user) return null;
console.log(initData.user.firstName);

Ошибка 3: Забыть про cleanup в useEffect

// ❌ Обработчик не снимается
useEffect(() => {
    mainButton.on('click', handleClick);
}, []);

// ✅
useEffect(() => {
    mainButton.on('click', handleClick);
    return () => mainButton.off('click', handleClick);
}, [mainButton]);

Ошибка 4: Тестировать только в браузере

Mini App в браузере и Mini App в Telegram — разные вещи. Обязательно тестируйте через ngrok или аналоги с реальным ботом. Как это настроить — в статье как создать Telegram Mini App.

Деплой и настройка бота

После разработки нужно:

  1. Собрать проект: npm run build
  2. Разместить dist/ на хостинге с HTTPS (например, Vercel, Netlify или собственный VDS)
  3. В BotFather: /newapp или /editapp → установить URL вашего деплоя
  4. Проверить через https://t.me/ваш_бот?startapp=

Telegram требует HTTPS — HTTP не работает.

Итог

@telegram-apps/sdk-react значительно упрощает разработку Mini Apps по сравнению с прямой работой через window.Telegram.WebApp. Основные выводы:

  • Инициализируйте SDK до монтирования React-дерева
  • Всегда верифицируйте initData на бэкенде — никогда не доверяйте клиентским данным
  • Следите за cleanup в useEffect для MainButton и BackButton
  • Используйте mockTelegramEnv для разработки без постоянного деплоя
  • Тестируйте финальную версию в реальном Telegram-клиенте

Если хотите сэкономить время и запустить готовое Mini App без погружения в технические детали — расскажите нам о своём проекте, мы возьмём разработку на себя.


Читайте также

  • Как создать Telegram Mini App: полная инструкция
  • VK Mini Apps или Telegram: где бизнес зарабатывает больше в 2026
  • Telegram Bot API 2026: новые возможности

Обсудим ваш проект?

Оставьте контакты — перезвоним и обсудим задачу

Содержание
  • Что такое @telegram-apps/sdk-react и зачем он нужен
  • Установка и настройка проекта
  • Инициализация SDK
  • SDKProvider — оборачиваем приложение
  • Получение данных пользователя: initDataUnsafe
  • MainButton — кнопка в нижней панели
  • BackButton — навигация назад
  • Viewport и адаптация к размеру экрана
  • CloudStorage — хранение данных без бэкенда
  • Типичные ошибки и как их избежать
  • Деплой и настройка бота
  • Итог
  • Читайте также
Поделиться:

Похожие статьи

Как создать Telegram Mini App: полная инструкция для разработчика
Mini Apps

Как создать Telegram Mini App: полная инструкция для разработчика

14 мин
VK Mini Apps или Telegram: где бизнес зарабатывает больше в 2026
Mini Apps

VK Mini Apps или Telegram: где бизнес зарабатывает больше в 2026

11 мин
Создаём Telegram Mini App на React: пошаговый туториал
Mini Apps

Создаём Telegram Mini App на React: пошаговый туториал

16 мин
Feature IT

Feature IT — платформа по обучению программированию и разработке цифровых продуктов. Мы создаём современные веб-решения для бизнеса и обучаем этому других!

Политика конфиденциальностиПользовательское соглашение

О компании

  • Блог
  • Карьера

Услуги разработки

  • Разработка сайтов под ключ
  • Веб-приложения на React/Next.js
  • Telegram-боты для бизнеса
  • Mini Apps (Telegram, VK)
  • SEO-оптимизированные сайты
  • Автоматизация бизнес-процессов
  • Поддержка и развитие IT-продуктов

Обучение

  • Курс Python с нуля
  • Алгоритмы и структуры данных
  • Паттерны проектирования
  • Подготовка к собеседованиям в IT
  • Практика на реальных проектах

Инструменты

  • Генератор UTM-меток
  • Счётчик символов