如何在React中搭建一个Telegram认证Hook(一步步教你)
制作React Hook来验证Telegram用户(一步一步教程)
嘿!👋 你有没有想过为你的应用自定义一个身份验证钩子?特别是针对 Telegram 吗?如果你正在 Telegram 平台上构建一些酷炫的东西,比如我的应用 代码优化 (稍后再详谈),你可能想要以一种无缝的方式管理你的用户。
在本文中,我来告诉你如何创建一个用于处理认证的 React 钩子,使用 Telegram 的 SDK。
基于什么选择Telegram的SDK?Telegram 有一个很酷的功能,用户可以通过 Telegram 本身登录,只需点击一下就可以获取他们的详细信息。这里的好处是,你不必担心复杂的 OAuth 认证流程。这种登录方式快速、简单且高度安全。结合使用 React hooks 和 Supabase(用于用户管理),你可以很快搞定认证。
好了,准备好了吗?让我们潜水吧! 🏊♂️ 步骤 1:设置钩子我们先从构建一个钩子开始,在 React 中,钩子就是用来复用有状态逻辑的工具。目标是通过 Telegram 的 SDK 获取用户信息并将其存入我们应用的全局状态。下面就是基本设置:
import { useEffect, useCallback } from 'react';
import { useLaunchParams } from '@telegram-apps/sdk-react';
import { useUserStore } from '@/store/userStore';
const useAuth = () => {
const lp = useLaunchParams(); // 从 Telegram 获取启动参数 lp
const setUser = useUserStore((state) => state.setUser); // 全局用户管理状态
const setIsNewUser = useUserStore((state) => state.setIsNewUser); // 新用户标志
const existingUserInState = useUserStore((state) => state.user); // 获取现有的用户信息
// 此处将添加更多功能
return { user: existingUserInState };
};
export default useAuth;
发生了什么事?
**useLaunchParams**
:这是来自@telegram-apps/sdk-react
包的一个钩子。它允许我们获取当有人通过 Telegram 启动你的应用时发送的用户信息。并将这些信息存储在变量lp
中。- 全局状态管理:我们使用全局存储(如
useUserStore
)来管理用户数据。这使得应用可以在需要的地方获取用户信息,保持代码的整洁。我使用 Zustand 来管理状态,但你也可以用Redux
、Context API
或其他任何状态管理方案来替代它。
现在已经从Telegram拿到了用户的数据,需要将这些数据存储到我们的数据库中(这里我使用的是Supabase)。不想在已有用户数据的情况下重复获取。这时就可以用上缓存机制和useCallback
钩子了。
我们给新用户增加一些逻辑处理吧
const signUpUser = useCallback(async () => {
const initDataResult = lp.initData;
const user = initDataResult?.user as AuthUser | undefined;
// 如果从Telegram的启动参数中获取到了用户数据
if (user) {
// 如果用户已经在状态中存在,避免不必要的数据库查询
if (existingUserInState && existingUserInState.id === user.id) {
console.log('用户已经在状态中存在,跳过重新查询');
return;
}
try {
// 检查用户是否已经在数据库中存在
const { data: existingUser, error: fetchError } = await supabase
.from('users')
.select('*')
.eq('id', user.id)
.single();
// 处理查询错误
if (fetchError) {
console.error('检索用户时出错:', fetchError);
return;
}
// 如果没有找到用户,则创建新用户
if (!existingUser) {
setIsNewUser(true);
const { data, error } = await supabase
.from('users')
.insert([
{
...user,
current_level: 1,
coins: 1000,
boosts: [{ Freeze: 10, Hint: 10 }],
},
])
.select()
.single();
if (error) {
console.error('插入用户数据时出错:', error);
} else {
console.log('用户已注册:', data);
setUser(data); // 更新全局状态为新用户
}
} else {
console.log('找到现有用户:', existingUser);
setUser(existingUser);
setIsNewUser(false);
}
} catch (error) {
console.error('用户注册过程中出现问题:', error);
}
}
}, [lp, setUser, setIsNewUser, existingUserInState]);
简单来说:
- 备忘录:
useCallback
钩子确保signUpUser
函数不会在每次渲染时重新创建,这有助于提升性能。 - 检查现有用户:如果用户已经在我们的全局状态中(通过
existingUserInState
检查),我们将跳过数据库调用。这可以节省不必要的 API 请求。 - 数据库检查:如果用户在 Supabase 中不存在,我们会为他们创建一个新条目,附带一些初始数据,比如
coins
、current_level
和boosts
。
现在我们希望用户在打开应用时自动登录。我们将使用 useEffect
钩子在组件加载时触发登录过程。
useEffect(() => {
signUpUser(); // 组件挂载时自动注册用户
}, [signUpUser]);
这是它为什么有效:
- useEffect:
useEffect
钩子确保注册流程仅在组件首次加载时执行一次。依赖数组中的[signUpUser]
确保只有当signUpUser
函数发生变化时才会调用,得益于useCallback
的功能。
最后,我们从我们的钩子返回用户,这样使用这个钩子的任何组件都可以获取当前用户数据。
返回 { user: existingUserInState };
完整的代码:
下面就是完整的 useAuth
钩子,用于认证。
import { useEffect, useCallback } from 'react';
import supabase from '@/supabaseClient';
import { useUserStore } from '@/store/userStore';
import { AuthUser } from '@/context/UserContext/interface';
import { useLaunchParams } from '@telegram-apps/sdk-react';
const useAuth = () => {
const lp = useLaunchParams();
const setUser = useUserStore((state) => state.setUser);
const setIsNewUser = useUserStore((state) => state.setIsNewUser);
const existingUserInState = useUserStore((state) => state.user);
const signUpUser = useCallback(async () => {
const initDataResult = lp.initData;
const user = initDataResult?.user as AuthUser | undefined;
if (user) {
if (existingUserInState && existingUserInState.id === user.id) {
console.log('用户已在状态中,跳过重新获取');
return;
}
try {
const { data: existingUser, error: fetchError } = await supabase
.from('users')
.select('*')
.eq('id', user.id)
.single();
if (fetchError) {
console.error('获取用户错误:', fetchError);
return;
}
if (!existingUser) {
setIsNewUser(true);
const { data, error } = await supabase
.from('users')
.insert([
{
...user,
current_level: 1,
coins: 1000,
boosts: [{ Freeze: 10, Hint: 10 }],
},
])
.select()
.single();
if (error) {
console.error('插入用户错误:', error);
} else {
console.log('用户注册成功:', data);
setUser(data);
}
} else {
console.log('用户已存在:', existingUser);
setUser(existingUser);
setIsNewUser(false);
}
} catch (error) {
console.error('用户注册过程中错误:', error);
}
}
}, [lp, setUser, setIsNewUser, existingUserInState]);
useEffect(() => {
signUpUser();
}, [signUpUser]);
return { user: existingUserInState };
};
export default useAuth;
如何帮助我们优化代码
代码提升(Code Boost)是指优化和增强代码的过程。以下是如何帮助我们在代码提升中获益的方法。
在 Code Boost 中,我们使用这个具体的钩子来通过 Telegram 管理用户认证。当用户打开应用,钩子会检查他们在数据库中是否已经存在。若不存在,则会自动注册,获得一些初始金币和游戏助推来开始使用。这一切都通过 Telegram SDK 和我们的 useAuth
钩子无缝完成。
Code Boost
⚡️如果你正在搭建类似的东西,欢迎查看Telegram中的Code Boost。这个钩子让你集成Telegram认证变得非常简单,现在你可以在自己的项目中轻松使用它!
⚡️闪电启动:点击这里
编程愉快!共同学习,写下你的评论
评论加载中...
作者其他优质文章