Skip to content

useInitData

获取 Telegram Mini App 的初始化数据,包括用户信息、启动参数等。这是实现 Telegram 认证的核心 Hook。

导入

tsx
import { useInitData } from '@xcloud/ui-telegram'

示例

基础使用

获取当前用户信息:

tsx
import { useInitData } from '@xcloud/ui-telegram'

function Profile() {
  const initData = useInitData()

  if (!initData.isAvailable) {
    return <div>Not in Telegram environment</div>
  }

  if (!initData.isLoaded) {
    return <div>Loading...</div>
  }

  return (
    <div>
      <h1>Hello, {initData.user?.firstName}!</h1>
      <p>ID: {initData.user?.id}</p>
      <p>Username: @{initData.user?.username}</p>
      <p>Language: {initData.user?.languageCode}</p>
    </div>
  )
}

使用启动参数

处理深链接和推荐系统:

tsx
import { useInitData } from '@xcloud/ui-telegram'
import { useEffect } from 'react'

function App() {
  const { startParam } = useInitData()

  useEffect(() => {
    if (startParam) {
      // 处理启动参数
      console.log('Started with param:', startParam)

      // 例如: 推荐系统
      if (startParam.startsWith('ref_')) {
        const referrerId = startParam.replace('ref_', '')
        trackReferral(referrerId)
      }

      // 例如: 深链接
      if (startParam.startsWith('product_')) {
        const productId = startParam.replace('product_', '')
        navigateToProduct(productId)
      }
    }
  }, [startParam])

  return <div>Your App</div>
}

后端认证

发送原始数据到后端进行验证:

tsx
import { useInitData } from '@xcloud/ui-telegram'
import { useEffect } from 'react'

function AuthComponent() {
  const { raw, hash, user, isLoaded } = useInitData()

  useEffect(() => {
    if (isLoaded && raw && hash) {
      // 发送到后端进行验证
      fetch('/api/auth/telegram', {
        method: 'POST',
        headers: {
          'Authorization': `tma ${raw}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          userId: user?.id,
          hash: hash,
        }),
      })
        .then(res => res.json())
        .then(data => {
          console.log('Authenticated:', data)
          localStorage.setItem('token', data.token)
        })
    }
  }, [raw, hash, user, isLoaded])

  return <div>Authenticating...</div>
}

用户头像和信息

显示完整的用户信息:

tsx
import { useInitData } from '@xcloud/ui-telegram'

function UserCard() {
  const { user, isLoaded } = useInitData()

  if (!isLoaded || !user) {
    return <div>Loading user info...</div>
  }

  return (
    <div className="user-card">
      {user.photoUrl && (
        <img src={user.photoUrl} alt={user.firstName} />
      )}
      <h2>{user.firstName} {user.lastName}</h2>
      {user.username && <p>@{user.username}</p>}
      <p>User ID: {user.id}</p>
      <p>Language: {user.languageCode}</p>
      {user.isPremium && <span className="badge">Premium</span>}
    </div>
  )
}

Hook API

返回值

typescript
interface TelegramInitData {
  // 用户信息
  user: User | undefined
  receiver: User | undefined

  // 聊天信息
  chat: any
  chatType: string | undefined
  chatInstance: string | undefined

  // 认证信息
  authDate: Date | undefined
  hash: string | undefined

  // 启动参数
  startParam: string | undefined

  // 其他
  canSendAfter: number | undefined
  raw: string | undefined  // 原始 initData 字符串(用于后端验证)

  // 状态
  isLoaded: boolean
  isAvailable: boolean
}

User 类型

typescript
interface User {
  id: number
  isBot?: boolean
  firstName: string
  lastName?: string
  username?: string
  languageCode?: string
  isPremium?: boolean
  photoUrl?: string
}

数据说明

user

当前用户信息,包含用户 ID、姓名、用户名等基本信息。

receiver

接收消息的用户(仅在通过 attachment menu 打开时存在)。

chat

聊天信息(如果从聊天中打开)。

authDate

认证时间(Unix 时间戳),可用于验证数据有效期。

hash

认证哈希值,用于后端验证数据完整性。

startParam

启动参数,可用于深链接、推荐系统等场景。

raw

原始的 initData 字符串,必须发送到后端进行签名验证。

isLoaded

数据是否已加载完成。

isAvailable

是否在 Telegram 环境中(非 Telegram 环境返回 false)。

常见场景

检查是否为高级用户

tsx
function PremiumFeature() {
  const { user } = useInitData()

  if (!user?.isPremium) {
    return (
      <div>
        <h3>Premium Feature</h3>
        <p>This feature is only available for Telegram Premium users.</p>
        <button>Upgrade to Premium</button>
      </div>
    )
  }

  return <div>Welcome, Premium User! 🌟</div>
}

多语言支持

tsx
import { useInitData } from '@xcloud/ui-telegram'
import { useEffect } from 'react'
import i18n from './i18n'

function App() {
  const { user } = useInitData()

  useEffect(() => {
    if (user?.languageCode) {
      // 根据用户的 Telegram 语言设置切换应用语言
      i18n.changeLanguage(user.languageCode)
    }
  }, [user?.languageCode])

  return <div>{/* Your app */}</div>
}

验证数据有效期

tsx
import { useInitData } from '@xcloud/ui-telegram'
import { useEffect } from 'react'

function SecurityCheck() {
  const { authDate, isLoaded } = useInitData()

  useEffect(() => {
    if (isLoaded && authDate) {
      const now = new Date()
      const ageInHours = (now.getTime() - authDate.getTime()) / (1000 * 60 * 60)

      if (ageInHours > 1) {
        console.warn('Init data is older than 1 hour, may be invalid')
        // 重新加载或提示用户
      }
    }
  }, [authDate, isLoaded])

  return <div>Security check...</div>
}

注意事项

  1. 必须在 TelegramProvider 中使用: 确保应用被 TelegramProvider 包裹
  2. 数据只读: initData 在应用生命周期内不会改变
  3. 异步加载: 使用 isLoaded 判断数据是否已加载
  4. 环境检查: 使用 isAvailable 检查是否在 Telegram 环境
  5. 安全性: 后端必须验证 hashauthDate,不能仅信任客户端数据
  6. 有效期: Telegram 建议 initData 的有效期为 1 小时

最佳实践

完整的认证流程

tsx
import { useInitData } from '@xcloud/ui-telegram'
import { useState, useEffect } from 'react'

function AuthFlow() {
  const initData = useInitData()
  const [authState, setAuthState] = useState<'loading' | 'success' | 'error'>('loading')

  useEffect(() => {
    async function authenticate() {
      if (!initData.isLoaded) return

      if (!initData.isAvailable) {
        setAuthState('error')
        return
      }

      try {
        const response = await fetch('/api/auth', {
          method: 'POST',
          headers: {
            'Authorization': `tma ${initData.raw}`,
            'Content-Type': 'application/json',
          },
        })

        if (response.ok) {
          const data = await response.json()
          localStorage.setItem('token', data.token)
          setAuthState('success')
        } else {
          setAuthState('error')
        }
      } catch (error) {
        setAuthState('error')
      }
    }

    authenticate()
  }, [initData.isLoaded, initData.isAvailable, initData.raw])

  if (authState === 'loading') return <div>Authenticating...</div>
  if (authState === 'error') return <div>Authentication failed</div>

  return <div>Welcome, {initData.user?.firstName}!</div>
}

相关链接

基于 MIT 许可发布