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

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

Пошаговый туториал по созданию Telegram Mini App на React: от инициализации проекта до деплоя. Telegram SDK, навигация, оплата.

Редакция Feature
Редакция Feature·
20 мар
·
16 мин
·
Создаём Telegram Mini App на React: пошаговый туториал

Введение: почему React — лучший выбор для Mini App

Telegram Mini Apps — это веб-приложения, работающие внутри мессенджера. А раз это веб, значит, для разработки подходят любые современные фреймворки. Но React остаётся самым популярным выбором: огромная экосистема библиотек, знакомый разработчикам синтаксис и отличная совместимость с Telegram WebApp SDK.

В этом туториале мы пройдём весь путь — от npm create до деплоя. Создадим Mini App с реальной функциональностью: авторизацией пользователя, адаптацией под тему Telegram, навигацией, платежами и haptic feedback. Общее представление о платформе Mini Apps можно получить в нашей обзорной статье.

1. Инициализация проекта: Vite + React + TypeScript

Для сборки используем Vite — он обеспечивает мгновенный hot reload и оптимальный продакшен-бандл.

Создание проекта

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

Структура проекта

Организуем код по функциональным модулям:

src/
├── components/       # UI-компоненты
│   ├── ui/          # Базовые элементы (Button, Input, Card)
│   └── layout/      # Layout-компоненты (Header, Page)
├── hooks/           # Кастомные хуки
│   ├── useTelegram.ts
│   └── useTheme.ts
├── pages/           # Страницы приложения
├── services/        # API-клиент и бизнес-логика
├── types/           # TypeScript-типы
├── utils/           # Утилиты
├── App.tsx
└── main.tsx

Такая структура масштабируется: при росте приложения добавляются новые модули, а не растут существующие файлы.

Настройка Vite

Для корректной работы Mini App нужно настроить несколько параметров Vite:

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  server: {
    host: true, // Доступ с мобильного устройства в локальной сети
    port: 3000,
  },
  build: {
    outDir: "dist",
    sourcemap: false,
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ["react", "react-dom"],
        },
      },
    },
  },
});

2. Подключение Telegram WebApp SDK

Установка SDK

Telegram предоставляет официальный npm-пакет:

npm install @telegram-apps/sdk-react

Этот пакет включает React-хуки для работы с Telegram API. Альтернативно можно использовать низкоуровневый @telegram-apps/sdk, но React-обёртка удобнее.

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

Создадим провайдер, который инициализирует SDK при загрузке приложения:

// src/components/TelegramProvider.tsx
import {useEffect, useState, ReactNode} from 'react'
import {init, backButton, miniApp} from '@telegram-apps/sdk-react'

interface Props {
    children: ReactNode
}

export function TelegramProvider({children}: Props) {
    const [ready, setReady] = useState(false)

    useEffect(() => {
        const initApp = async () => {
            try {
                init()
                miniApp.ready()
                setReady(true)
            } catch (error) {
                console.error('Failed to init Telegram SDK:', error)
                // Fallback для разработки в браузере
                setReady(true)
            }
        }
        initApp()
    }, [])

    if (!ready) return <div>Loading
...
    </div>
    return <>{children} < />
}

Обёртка в main.tsx

// src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import {TelegramProvider} from './components/TelegramProvider'
import App from './App'
import './index.css'

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

3. Адаптация темы под Telegram

Одно из ключевых требований к Mini App — визуальная интеграция с Telegram. Приложение должно выглядеть как часть мессенджера, а не как чужеродная вставка.

CSS-переменные Telegram

Telegram передаёт цветовую схему через CSS-переменные. Основные переменные:

:root {
  --tg-theme-bg-color: #ffffff;
  --tg-theme-text-color: #000000;
  --tg-theme-hint-color: #999999;
  --tg-theme-link-color: #2481cc;
  --tg-theme-button-color: #5288c1;
  --tg-theme-button-text-color: #ffffff;
  --tg-theme-secondary-bg-color: #efeff3;
}

Глобальные стили

/* src/index.css */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family:
    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background-color: var(--tg-theme-bg-color, #ffffff);
  color: var(--tg-theme-text-color, #000000);
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--tg-theme-link-color, #2481cc);
}

Кастомный хук для темы

Создадим хук, который удобно предоставляет цвета темы в компонентах:

// src/hooks/useTheme.ts
import { useMemo } from "react";
import { useThemeParams } from "@telegram-apps/sdk-react";

export function useAppTheme() {
  const themeParams = useThemeParams();

  return useMemo(
    () => ({
      bgColor: themeParams.bgColor || "#ffffff",
      textColor: themeParams.textColor || "#000000",
      hintColor: themeParams.hintColor || "#999999",
      linkColor: themeParams.linkColor || "#2481cc",
      buttonColor: themeParams.buttonColor || "#5288c1",
      buttonTextColor: themeParams.buttonTextColor || "#ffffff",
      secondaryBgColor: themeParams.secondaryBgColor || "#efeff3",
      isDark: themeParams.bgColor
        ? parseInt(themeParams.bgColor.slice(1), 16) < 0x808080
        : false,
    }),
    [themeParams]
  );
}

Теперь компоненты автоматически подстраиваются под светлую и тёмную тему Telegram. Если вас интересуют продвинутые приёмы адаптивной вёрстки, рекомендуем нашу статью про адаптивный дизайн с Tailwind CSS.

4. Навигация в Mini App

Выбор подхода

В Mini App есть нативная кнопка «Назад» в шапке Telegram. Это значит, что навигация должна быть интегрирована с этой кнопкой. Используем react-router-dom:

npm install react-router-dom

Настройка роутера

// src/App.tsx
import {BrowserRouter, Routes, Route, useNavigate, useLocation} from 'react-router-dom'
import {useEffect} from 'react'
import {backButton} from '@telegram-apps/sdk-react'
import {HomePage} from './pages/HomePage'
import {ProductPage} from './pages/ProductPage'
import {CartPage} from './pages/CartPage'

function NavigationHandler() {
    const navigate = useNavigate()
    const location = useLocation()

    useEffect(() => {
        if (location.pathname !== '/') {
            backButton.show()
        } else {
            backButton.hide()
        }

        const off = backButton.onClick(() => {
            navigate(-1)
        })

        return () => off()
    }, [location, navigate])

    return null
}

export default function App() {
    return (
        <BrowserRouter>
            <NavigationHandler / >
        <Routes>
            <Route path = "/"
    element = { < HomePage / >
}
    />
    < Route
    path = "/product/:id"
    element = { < ProductPage / >
}
    />
    < Route
    path = "/cart"
    element = { < CartPage / >
}
    />
    < /Routes>
    < /BrowserRouter>
)
}

Важные нюансы навигации

Несколько моментов, которые часто упускают:

  • Не используйте хеш-роутинг — BrowserRouter лучше работает с Telegram
  • Кнопка «Назад» должна быть предсказуемой — пользователь ожидает, что она вернёт на предыдущий экран
  • Глубина навигации — старайтесь не делать более 3–4 уровней вложенности
  • Анимации переходов — добавляют ощущение нативности, используйте framer-motion

5. Аутентификация пользователя

Как работает initData

При запуске Mini App Telegram передаёт подписанную строку initData, содержащую информацию о пользователе. Эту строку нужно проверить на бэкенде — чтобы убедиться, что данные подлинные.

Получение initData на фронте

// src/hooks/useAuth.ts
import { useLaunchParams } from "@telegram-apps/sdk-react";

export function useAuth() {
  const launchParams = useLaunchParams();

  const initData = launchParams.initDataRaw;
  const user = launchParams.initData?.user;

  return {
    initData,
    user,
    isAuthenticated: !!user,
    userId: user?.id,
    firstName: user?.firstName,
    lastName: user?.lastName,
    username: user?.username,
    isPremium: user?.isPremium,
    languageCode: user?.languageCode,
    photoUrl: user?.photoUrl,
  };
}

Валидация на бэкенде (Node.js)

// server/auth.ts
import crypto from "crypto";

function validateInitData(initData: string, botToken: string): boolean {
  const params = new URLSearchParams(initData);
  const hash = params.get("hash");
  params.delete("hash");

  const dataCheckString = Array.from(params.entries())
    .sort(([a], [b]) => a.localeCompare(b))
    .map(([key, value]) => `${key}=${value}`)
    .join("\n");

  const secretKey = crypto
    .createHmac("sha256", "WebAppData")
    .update(botToken)
    .digest();

  const calculatedHash = crypto
    .createHmac("sha256", secretKey)
    .update(dataCheckString)
    .digest("hex");

  return calculatedHash === hash;
}

Эта проверка гарантирует, что данные пришли именно от Telegram и не были подменены. Без неё любой может подделать запрос к вашему API.

Нужна разработка Mini App?

Создадим Mini App на React с полным функционалом

Заказать Mini App

6. Взаимодействие с бэкендом

API-клиент

Создадим обёртку для fetch с автоматической передачей initData:

// src/services/api.ts
const API_URL = import.meta.env.VITE_API_URL || "https://api.example.com";

class ApiClient {
  private initData: string = "";

  setInitData(data: string) {
    this.initData = data;
  }

  async request<T>(path: string, options: RequestInit = {}): Promise<T> {
    const response = await fetch(`${API_URL}${path}`, {
      ...options,
      headers: {
        "Content-Type": "application/json",
        "X-Init-Data": this.initData,
        ...options.headers,
      },
    });

    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }

    return response.json();
  }

  get<T>(path: string) {
    return this.request<T>(path);
  }

  post<T>(path: string, body: unknown) {
    return this.request<T>(path, {
      method: "POST",
      body: JSON.stringify(body),
    });
  }
}

export const api = new ApiClient();

Хук для загрузки данных

// src/hooks/useApi.ts
import { useState, useEffect } from "react";
import { api } from "../services/api";

export function useApi<T>(path: string) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    api
      .get<T>(path)
      .then(setData)
      .catch((e) => setError(e.message))
      .finally(() => setLoading(false));
  }, [path]);

  return { data, loading, error };
}

7. Платежи через Telegram Stars

Как работают Telegram Stars

Telegram Stars — внутренняя валюта платформы. Пользователи покупают Stars через Apple Pay или Google Pay, а затем тратят их в Mini Apps. Разработчик получает средства и может вывести их через Fragment.

Создание инвойса на бэкенде

// server/payments.ts
import { Bot } from "grammy";

const bot = new Bot(process.env.BOT_TOKEN!);

async function createInvoice(
  userId: number,
  title: string,
  description: string,
  amount: number
) {
  const invoiceLink = await bot.api.createInvoiceLink(
    title,
    description,
    JSON.stringify({ userId, amount }), // payload
    "", // provider_token (пусто для Stars)
    "XTR", // currency (XTR = Stars)
    [{ label: title, amount }] // prices
  );

  return invoiceLink;
}

Оплата на фронте

// src/hooks/usePayment.ts
import { miniApp } from "@telegram-apps/sdk-react";
import { api } from "../services/api";

export function usePayment() {
  const pay = async (productId: string) => {
    // Получаем ссылку на инвойс с бэкенда
    const { invoiceLink } = await api.post<{ invoiceLink: string }>(
      "/payments/create",
      { productId }
    );

    // Открываем окно оплаты Telegram
    const result = await miniApp.openInvoice(invoiceLink);

    if (result === "paid") {
      // Оплата успешна
      return true;
    }

    return false;
  };

  return { pay };
}

Обработка webhook

Telegram отправит webhook при успешной оплате. Бэкенд должен подтвердить получение:

// server/webhook.ts
bot.on("pre_checkout_query", async (ctx) => {
  // Проверяем, можем ли выполнить заказ
  await ctx.answerPreCheckoutQuery(true);
});

bot.on("message:successful_payment", async (ctx) => {
  const payment = ctx.message.successful_payment;
  const payload = JSON.parse(payment.invoice_payload);

  // Выдаём пользователю оплаченный товар/услугу
  await fulfillOrder(payload.userId, payload.amount);

  await ctx.reply("Оплата прошла успешно!");
});

8. Haptic Feedback и нативные функции

Haptic Feedback

Вибрационная обратная связь делает Mini App ощутимо нативнее. Telegram предоставляет три типа:

// src/hooks/useHaptic.ts
import { hapticFeedback } from "@telegram-apps/sdk-react";

export function useHaptic() {
  return {
    // Лёгкий тап — для нажатия кнопок
    impact: (
      style: "light" | "medium" | "heavy" | "rigid" | "soft" = "light"
    ) => {
      hapticFeedback.impactOccurred(style);
    },
    // Уведомление — для результатов действий
    notification: (type: "success" | "warning" | "error") => {
      hapticFeedback.notificationOccurred(type);
    },
    // Изменение выбора — для переключателей
    selectionChanged: () => {
      hapticFeedback.selectionChanged();
    },
  };
}

Пример использования в компоненте

function ProductCard({product}: { product: Product }) {
    const {impact, notification} = useHaptic()
    const {pay} = usePayment()

    const handleBuy = async () => {
        impact('medium')
        const success = await pay(product.id)
        notification(success ? 'success' : 'error')
    }

    return (
        <div className = "product-card" >
            <h3>{product.name} < /h3>
            < p > {product.price}
    Stars < /p>
    < button
    onClick = {handleBuy} > Купить < /button>
        < /div>
)
}

QR-сканер

import { qrScanner } from "@telegram-apps/sdk-react";

async function scanQR() {
  const result = await qrScanner.open({ text: "Наведите камеру на QR-код" });
  if (result) {
    console.log("Scanned:", result);
  }
  qrScanner.close();
}

Cloud Storage

import { cloudStorage } from "@telegram-apps/sdk-react";

// Сохранить данные
await cloudStorage.setItem("cart", JSON.stringify(cartItems));

// Загрузить данные
const saved = await cloudStorage.getItem("cart");
const cart = saved ? JSON.parse(saved) : [];

9. Тестирование и отладка

Локальная разработка

Для тестирования Mini App локально нужен HTTPS. Используем ngrok или Cloudflare Tunnel:

# Запускаем dev-сервер
npm run dev

# В другом терминале — туннель
npx cloudflared tunnel --url http://localhost:3000

Полученный HTTPS-URL указываем в @BotFather как URL Mini App.

Debug Mode

В Telegram Desktop можно включить Debug Mode: правый клик по Mini App и выбрать «Inspect Element». Откроется Chrome DevTools с полным доступом к консоли, сети и элементам.

На мобильных устройствах используйте eruda — встроенную консоль для мобильного веба:

npm install eruda
// Только для разработки!
if (import.meta.env.DEV) {
  import("eruda").then((eruda) => eruda.default.init());
}

Тестирование без Telegram

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

// src/utils/mockTelegram.ts
export function mockTelegramEnv() {
  if (typeof window !== "undefined" && !window.Telegram) {
    window.Telegram = {
      WebApp: {
        initData: "mock_init_data",
        initDataUnsafe: {
          user: {
            id: 12345,
            first_name: "Test",
            last_name: "User",
            username: "testuser",
          },
        },
        ready: () => {},
        expand: () => {},
        close: () => {},
        // ... другие методы
      },
    } as any;
  }
}

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

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

10. Деплой Mini App

Вариант 1: Vercel

Самый простой способ задеплоить Mini App:

npm install -g vercel
vercel

Vercel автоматически определит Vite-проект, соберёт его и задеплоит. Вы получите HTTPS-URL, который можно сразу указать в @BotFather.

Вариант 2: Cloudflare Pages

Бесплатный хостинг с отличной производительностью:

npm install -g wrangler
wrangler pages deploy dist

Вариант 3: VPS с Nginx

Для полного контроля можно разместить Mini App на VPS:

server {
    listen 443 ssl;
    server_name mini-app.example.com;

    ssl_certificate /etc/letsencrypt/live/mini-app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mini-app.example.com/privkey.pem;

    root /var/www/mini-app/dist;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

Настройка бота в BotFather

После деплоя настройте бота:

  1. Откройте @BotFather
  2. Выберите бота: /mybots -> ваш бот
  3. Bot Settings -> Menu Button -> укажите URL Mini App
  4. Или Bot Settings -> Mini App -> укажите URL

CI/CD

Автоматизируйте деплой через GitHub Actions:

name: Deploy Mini App
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npm run build
      - uses: cloudflare/pages-action@v1
        with:
          apiToken: ${{ secrets.CF_API_TOKEN }}
          accountId: ${{ secrets.CF_ACCOUNT_ID }}
          projectName: my-mini-app
          directory: dist

Подробнее о настройке мониторинга и CI/CD для веб-приложений можно прочитать в нашей отдельной статье.

Архитектурные решения и рекомендации

Производительность

Mini App работает в WebView, поэтому каждый килобайт на счету:

  • Минимизируйте бандл — используйте tree shaking, lazy loading для страниц
  • Оптимизируйте изображения — WebP, lazy loading, правильные размеры
  • Кэшируйте данные — используйте React Query или SWR для кэширования API-запросов
  • Избегайте тяжёлых библиотек — date-fns вместо moment, zod вместо yup

Оффлайн-поддержка

Mini App может ограниченно работать офлайн через Service Worker. Кэшируйте статику и критичные данные.

Аналитика

Подключите аналитику для понимания поведения пользователей:

  • Telegram предоставляет базовую статистику через @BotFather
  • Для детальной аналитики используйте Amplitude или Mixpanel
  • Отслеживайте воронку: открытие -> взаимодействие -> конверсия

Заключение

Мы прошли полный путь создания Telegram Mini App на React: от инициализации проекта до деплоя. Ключевые моменты:

  1. Vite + React + TypeScript — оптимальный стек для Mini App
  2. Telegram SDK — предоставляет всё необходимое для интеграции
  3. Адаптация темы — обязательна для нативного ощущения
  4. initData — безопасная аутентификация без регистрации
  5. Telegram Stars — простой способ монетизации
  6. Haptic feedback — мелочь, которая делает приложение живым

Если вам нужна помощь с разработкой Mini App — обращайтесь. Мы создаём Mini Apps на React с полным циклом: от проектирования до запуска и поддержки. Также можем подключить вашу IT-инфраструктуру для бесперебойной работы приложения.

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

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

Содержание
  • Введение: почему React — лучший выбор для Mini App
  • 1. Инициализация проекта: Vite + React + TypeScript
  • 2. Подключение Telegram WebApp SDK
  • 3. Адаптация темы под Telegram
  • 4. Навигация в Mini App
  • 5. Аутентификация пользователя
  • 6. Взаимодействие с бэкендом
  • 7. Платежи через Telegram Stars
  • 8. Haptic Feedback и нативные функции
  • 9. Тестирование и отладка
  • 10. Деплой Mini App
  • Архитектурные решения и рекомендации
  • Заключение
Поделиться:

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

Telegram Mini App на Next.js: почему SDK падает на сервере
Mini Apps

Telegram Mini App на Next.js: почему SDK падает на сервере

13 мин
@telegram-apps/sdk-react: белый экран и ошибки инициализации Mini App
Mini Apps

@telegram-apps/sdk-react: белый экран и ошибки инициализации Mini App

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

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

12 мин
Feature IT

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

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

О компании

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

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

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

Обучение

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

Инструменты

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