@daveyplate/better-auth-tanstack

中文文档
1.3.6发布于 2025/05/31MITTypeScriptESM + CJS零依赖近 30 天下载 107.4万

玉米片的钩子,换个更好的

中文使用文档
文档目录21 节
  1. 先决条件
  2. 安装
  3. 建立认证查询程序
  4. 应用程序/提供者.tsx
  5. 应用程序/layout.tsx
  6. AuthQuery 提供支持
  7. 创建 auth-hooks.ts
  8. 用钩子
  9. 使用会议
  10. 使用脚本
  11. 使用列表账户
  12. 使用量
  13. 使用列表会议
  14. 使用列表
  15. 使用列表Passkeys
  16. 变异 - 更新用户
  17. 服务器- Side 预选 - 高级使用
  18. SSR 会前会议
  19. 使用认证查询
  20. 认证混合
  21. 许可证

@daveyplate/ 更好的- auth- tanstack (中文(简体) )

Tanstack 查询钩为更好的奥特。 更严格地控制请求何时发出,乐观地突变,并通过Persist Cients支持离线缓存以获取离线授权.

更多即将到来... (例如更多的SSR预选,组织与条纹插件钩子,SWR端口. )

☕️ 给我买杯咖啡

先决条件

首先,你需要安装和整合 更好的认证 打开 Tanstack 查询。 。 。 .

安装

小时

pnpm add @daveyplate/better-auth-tanstack@latest

无

npm install @daveyplate/better-auth-tanstack@latest

给 useSession 钩子可以刷新签入、签出和签入时无需电子邮件验证,您必须手动拨打 refetch 或者说 queryClient.resetQueries() 页:1 ["session"] 输入 onSuccess 在等待和检查出错后召回其中每个函数.

如果您正在使用 Next.js App 路由器和受保护的中间软件路线, router.refresh() 还需要清除路由器缓存.

@daveyplate/ 更好 - auth - ii 更好的Auth UI支持更好的Auth-tanstack出盒子! 你只需要用这个 AuthUIProviderTanstack。 。 。 .

建立认证查询程序

首先,你需要设置 AuthQueryProvider 在您的申请。 此提供者将为钩子的功能提供必要的上下文. 要求数 "use client" next.js App路由器指令 .

应用程序/提供者.tsx

"use client"

import { AuthQueryProvider } from "@daveyplate/better-auth-tanstack"

export default function Providers({
  children,
}: {
  children: React.ReactNode
}) {
    return (
        <AuthQueryProvider>
            {children}
        </AuthQueryProvider>
    )
}

应用程序/layout.tsx

import { Providers } from "./providers"

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
    return (
        <Providers>
            {children}
        </Providers>
    )
}

AuthQuery 提供支持

这个 AuthQueryProvider 组件接受以下道具。 默认 staleTime 页:1 useSession 60秒时 useToken 10分钟.

Prop类型说明
查询选项 ?使用查询选项提供者的可选查询选项 .
会话查询选项?使用查询选项会话查询的可选查询选项.
符号查询选项 ?使用查询选项符号查询的可选查询选项 .
会场钥匙?字符串 []会话查询的可选密钥 。 默认是 ["session"]。 。 。 .
钥匙?字符串 []符号查询的可选密钥 。 默认是 ["token"]。 。 。 .
列表账户键 ?字符串 []列表账户查询的可选密钥 。 默认是 ["list-accounts"]。 。 。 .
会话列表 Key?字符串 []列表会议查询的可选密钥 。 默认是 ["list-sessions"]。 。 。 .
乐观?布尔是否执行乐观更新 。 默认是 true。 。 。 .
电磁?布尔变异后是否进行回溯 。 默认是 true。 。 。 .

创建 auth-hooks.ts

创建名为的文件 auth-hooks.ts 并使用 createAuthHooks 函数。 此函数取 authClient 实例,然后以完整的类型安全返回钩子,并从您的 authClient。 。 。 .

import { createAuthHooks } from "@daveyplate/better-auth-tanstack"
import { authClient } from "@/lib/auth-client"

export const authHooks = createAuthHooks(authClient)

export const {
    useSession,
    usePrefetchSession,
    useToken,
    useListAccounts,
    useListSessions,
    useListDeviceSessions,
    useListPasskeys,
    useUpdateUser,
    useUnlinkAccount,
    useRevokeOtherSessions,
    useRevokeSession,
    useRevokeSessions,
    useSetActiveSession,
    useRevokeDeviceSession,
    useDeletePasskey,
    useAuthQuery,
    useAuthMutation
} = authHooks

用钩子

使用会议

这个 useSession 钩子用来获取会话 .

道具

Prop类型说明
选项?使用查询选项会话查询的可选查询选项.

示例

import { useSession } from "@/hooks/auth-hooks"

function MyComponent() {
    const { 
        data: sessionData, 
        session, 
        user, 
        isPending, 
        refetch, 
        error
    } = useSession()

    if (isPending) return <div>Loading...</div>

    return <div>Welcome, {user?.email}</div>
}

使用脚本

这个 useToken 如果启用了更好的- 自动 JWT 插件, 钩子可以获取 JWT 令牌 .

道具

Prop类型说明
选项?使用查询选项符号查询的可选查询选项 .

示例

import { useToken } from "@/hooks/auth-hooks"

function MyComponent() {
    const { data, token, payload, isPending, error } = useToken()

    if (isPending) return <div>Loading...</div>

    return <div>JWT: {token}</div>
}

使用列表账户

这个 useListAccounts 勾通允许您列出和管理链接到不同提供者的用户账户.

使用量

import { useListAccounts } from "@/hooks/auth-hooks"

function AccountList() {
  const { data: accounts, isPending, error } = useListAccounts()

  if (isPending) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>

  return (
    <div>
      <h2>Linked Accounts</h2>
      <ul>
        {accounts?.map(account => (
          <li key={account.id}>
            {account.provider}
            <button onClick={() => unlinkAccount(account.provider)}>Unlink</button>
          </li>
        ))}
      </ul>
    </div>
  )
}

使用 unlinkAccount 函数以解开一个账户的提供者ID。 这是乐观的例子。 见下文非乐观的例子.

unlinkAccount({ providerId: "github" })

使用列表会议

import { useListSessions, useRevokeSession } from "@/hooks/auth-hooks"

function SessionList() {
  const { 
    data: sessions, 
    isPending,
    error
   } = useListSessions()
   const { mutate: revokeSession } = useRevokeSession()

  if (isPending) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>

  return (
    <div>
      <h2>Active Sessions</h2>
      <ul>
        {sessions?.map(session => (
          <li key={session.id}>
            {session.userAgent}
            <button onClick={() => revokeSession(session.token)}>Revoke</button>
          </li>
        ))}
      </ul>
    </div>
  )
}

使用列表

  const { 
    data: deviceSessions, 
    isPending,
    error
   } = useListDeviceSessions()

使用列表Passkeys

const {
    data: passkeys,
    isPending,
    error
} = useListPasskeys()

变异 - 更新用户

乐观范例

无加载器更新用户名的优化示例. 优化更新 Tanstack Query 缓存中的用户 。 对成功进行修正,对错误进行恢复。 使用默认设置用于 optimistic (真实) 道具在 AuthQueryProvider。 。 。 .

此软件包支持 Tanstack 查询全局错误配置 :

queryClient.getQueryCache().config.onError 自动调用, 这样您就可以设置全局错误托盘来显示 error.message || error.statusText。 。 。 . Tanstack 查询全局错误调用

"use client"

import { useState } from "react"

import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { useSession, useUpdateUser } from "@/hooks/auth-hooks"

export default function SettingsPage() {
    const { user, isPending } = useSession()
    const { mutate: updateUser, error: updateError } = useUpdateUser()
    const [disabled, setDisabled] = useState(true)

    const updateProfile = (formData: FormData) => {
        const name = formData.get("name") as string

        setDisabled(true)
        updateUser({ name: name })
    }

    useEffect(() => {
        if (updateError) {
            // Show an error Toast
        }
    }, [updateError])

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

    return (
        <div className="flex flex-col items-center gap-4 my-auto">
            <Card className="w-full max-w-md">
                <CardHeader>
                    <CardTitle>
                        Change Name
                    </CardTitle>
                </CardHeader>

                <CardContent>
                    <form
                        action={updateProfile}
                        className="flex flex-col gap-4 items-start"
                    >
                        <Label htmlFor="name">
                            Name
                        </Label>

                        <Input
                            defaultValue={user.name}
                            name="name"
                            placeholder="Name"
                            onChange={() => setDisabled(false)}
                        />

                        <Button disabled={disabled}>
                            Save
                        </Button>
                    </form>
                </CardContent>
            </Card>
        </div>
    )
}

不理想的例子

不理想的例子 useActionState 以显示更新用户名的加载器。 设定 optimistic 改为 false 输入 AuthQueryProvider 禁用乐观缓存更新的道具 。 发送请求到 /api/auth/update-user 然后在请求成功后更新 Tanstack 查询缓存中的用户。 然后通过调试重新验证会话.

注意我们使用 updateUserAsync

"use client"

import { Loader2 } from "lucide-react"
import { useActionState } from "react"

import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { useSession, useUpdateUser } from "@/hooks/auth-hooks"
import { cn } from "@/lib/utils"

export default function SettingsPage() {
    const { user, isPending } = useSession()
    const { mutate: updateUser, error: updateError } = useUpdateUser()
    const [disabled, setDisabled] = useState(true)

    type ActionState = Parameters<typeof updateUser>[0]

    const updateProfile = async (_: ActionState, formData: FormData) => {
        const name = formData.get("name") as string

        setDisabled(true)

        const { error } = await updateUserAsync({ name, fetchOptions: { throw: false } })

        if (error) {
            // Show an error Toast or throw an error to an ErrorBoundary

            setDisabled(false)
        }

        return { name } as ActionState
    }

    const [state, action, isSubmitting] = useActionState(updateProfile, {})

    // useEffect(() => {
    //     if (updateError) {
    //          setDisabled(false)
    //         // Show an error Toast
    //     }
    // }, [updateError])

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

    return (
        <div className="flex flex-col items-center gap-4 my-auto">
            <Card className="w-full max-w-md">
                <CardHeader>
                    <CardTitle>
                        Change Name
                    </CardTitle>
                </CardHeader>

                <CardContent>
                    <form
                        action={action}
                        className="flex flex-col gap-4 items-start"
                    >
                        <Label htmlFor="name">
                            Name
                        </Label>

                        <Input
                            defaultValue={state?.name ?? user.name}
                            name="name"
                            placeholder="Name"
                            onChange={() => setDisabled(false)}
                        />

                        <Button disabled={isSubmitting || disabled}>
                            <span className={cn(isSubmitting && "opacity-0")}>
                                Save
                            </span>

                            {isSubmitting && <Loader2 className="animate-spin absolute" />}
                        </Button>
                    </form>
                </CardContent>
            </Card>
        </div>
    )
}

服务器- Side 预选 - 高级使用

如果您想要使用混合预选策略, 则完全支持此策略 .

Tanstack 查询 - 高级服务器渲染

SSR 会前会议

这个 prefetchSession 函数在服务器中用于预取会话数据并存储在查询客户端中.

道具

Prop类型说明
认证认证服务器认证实例 .
查询客户端查询客户端查询客户端实例 .
页眉页眉信头对服务器请求有异议 .
查询 Key ?字符串 []会话查询的可选密钥 。 默认是 ["session"]。 。 。 .

RSC 示例

import { prefetchSession } from "@daveyplate/better-auth-tanstack/server"
import { HydrationBoundary, QueryClient, dehydrate } from "@tanstack/react-query"
import { headers } from "next/headers"

import { betterAuth } from "better-auth"
import { auth } from "@/lib/auth"

export default async function Page() {
    const queryClient = new QueryClient()

    const { data, session, user } = await prefetchSession(
        auth, queryClient, await headers()
    )

    return (
        <HydrationBoundary state={dehydrate(queryClient)}>
            <ClientPage />
        </HydrationBoundary>
    )
}

使用认证查询

import type { AnyUseQueryOptions } from "@tanstack/react-query"
import { useAuthQuery } from "@/lib/auth-hooks"
import { authClient } from "@/lib/auth-client"

export function useListDeviceSessions(
    options?: Partial<AnyUseQueryOptions>
) {
    return useAuthQuery({
        queryKey: ["device-sessions"],
        queryFn: authClient.multiSession.listDeviceSessions,
        options
    })
}

认证混合

import { AuthQueryContext, type AuthQueryOptions } from "@daveyplate/better-auth-tanstack"
import { authClient } from "@/lib/auth-client"
import { useAuthMutation } from "@/lib/auth-hooks"

export function useUpdateUser(
    options?: Partial<AuthQueryOptions>
) {
    type SessionData = typeof authClient["$Infer"]["Session"]
    const { sessionKey: queryKey } = useContext(AuthQueryContext)

    return useAuthMutation({
        queryKey,
        mutationFn: authClient.updateUser,
        optimisticData: (params, previousSession: SessionData) => ({
            ...previousSession,
            user: { ...previousSession.user, ...params }
        }),
        options
    })
}

许可证

这个项目根据麻省理工学院的许可证获得许可。 详情见LICENSE文件.

版本与发布记录

@daveyplate/better-auth-tanstack 共发布 46 个版本,首次发布于 2025/02/01;过去 12 个月发布了 0 个版本。

版本发布日期距今
1.3.6latest2025/05/311.4 年前
1.3.52025/05/181.5 年前
1.3.42025/04/151.6 年前
1.3.32025/04/081.6 年前
1.3.22025/04/051.6 年前
1.3.12025/04/041.6 年前

关于 @daveyplate/better-auth-tanstack 的常见问题

@daveyplate/better-auth-tanstack 是什么?

玉米片的钩子,换个更好的

如何安装 @daveyplate/better-auth-tanstack?

在项目目录运行 npm install @daveyplate/better-auth-tanstack,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=18.0.0)、react-dom(>=18.0.0)、better-auth(>=1.2.8)、@tanstack/query-core(>=5.65.0)、@tanstack/react-query(>=5.65.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@daveyplate/better-auth-tanstack 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@daveyplate/better-auth-tanstack 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@daveyplate/better-auth-tanstack 可以商用吗?

@daveyplate/better-auth-tanstack 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@daveyplate/better-auth-tanstack 的下载量有多少?

根据 npm 官方下载统计,@daveyplate/better-auth-tanstack 在 2026/10/12 – 2026/11/10 这 30 天内被下载 1,074,015 次,日均约 35,801 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@daveyplate/better-auth-tanstack 还在维护吗?

最新版本 1.3.6 发布于 2025/05/31(1.4 年前);至今共发布 46 个版本,其中过去 12 个月发布了 0 个;首次发布于 2025/02/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。