mcpField
C
clerk-react-router-patterns

clerk-react-router-patterns

github.com/clerk开发8915.6k 次安装今天更新
代码仓库

关于 clerk-react-router-patterns

面向 React Router v7/v8 项目的 Clerk 认证技能,适用于需要在中间件、loader、action 和客户端组件中处理认证的开发者。内容涵盖服务端认证数据传递及版本相关配置注意事项。

主要功能

  1. 01loader 与 action 中的认证
  2. 02中间件与根路由认证数据传递
  3. 03受保护路由和重定向
  4. 04客户端认证钩子
  5. 05React Router v7/v8 配置说明

适用场景

  1. 01在 loader 中按用户身份加载数据
  2. 02在 action 中验证身份后处理表单
  3. 03保护路由并重定向未登录用户
  4. 04在 SSR 应用中向客户端提供认证状态

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/clerk/skills --skill clerk-react-router-patterns

安装后在 Claude Code 中输入/clerk-react-router-patterns确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
loaders-actions.md
protected-routes.md
ssr-auth.md
templates/react-router-basic-auth/
package.json
react-router.config.ts
vite.config.ts
templates/react-router-basic-auth/app/
app.css
root.tsx
routes.ts
templates/react-router-basic-auth/app/routes/
home.tsx

详细介绍

React Router 模式

SDK:@clerk/react-router v3.5+。支持 React Router v7.9+ 和 v8。

你需要什么?

任务参考
在 loader 和 action 中进行身份验证references/loaders-actions.md
受保护的路由和重定向references/protected-routes.md
SSR 用户数据和会话references/ssr-auth.md

React Router v7 与 v8

在搭建项目之前,请检查已安装的 react-router 主版本——配置有所不同:

v7.9+v8+
中间件 API选择启用:在 react-router.config.ts 中设置 future: { v8_middleware: true }始终启用——切勿设置该标志(v8 已移除)
ssr.noExternal 变通方案(如下)不需要必须

最小设置

1. vite.config.ts(仅 v8——必需)

React Router v8 提供了开发/生产条件导出。在 react-router dev 中, Vite 会在 SSR 时将 @clerk/react-router 外部化,因此 Node 会解析 react-router 的生产构建, 而应用代码使用开发构建——产生两个模块实例和两个 Router 上下文。之后,每个请求都会在 SSR 期间失败,并报错:

Error: useNavigate() may be used only in the context of a <Router> component.

**npm ls react-router 显示只有一个副本——这并不能排除该问题。**重复发生在每种导出条件下,而不是已安装的副本之间。不要排查重复安装问题;请添加变通方案(上游问题: https://github.com/remix-run/react-router/issues/15232):

import { reactRouter } from '@react-router/dev/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [reactRouter()],
  ssr: {
    noExternal: ['@clerk/react-router'],
  },
})
2. root.tsx
import { Outlet } from 'react-router'
import { rootAuthLoader, clerkMiddleware } from '@clerk/react-router/server'
import { ClerkProvider } from '@clerk/react-router'
import type { Route } from './+types/root'

export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()]

export async function loader(args: Route.LoaderArgs) {
  return rootAuthLoader(args)
}

export default function App({ loaderData }: Route.ComponentProps) {
  return (
    <ClerkProvider loaderData={loaderData}>
      <Outlet />
    </ClerkProvider>
  )
}

@clerk/react-router 中没有 ClerkApp HOC(那是 @clerk/remix 的 API)。 在默认导出中渲染 <ClerkProvider loaderData={loaderData}>,并将根路由的 loaderData 传给它。

3. react-router.config.ts(仅 v7)
import type { Config } from '@react-router/dev/config'

export default {
  future: {
    v8_middleware: true,
  },
} satisfies Config

在 v8 中,完全省略 future 块——该标志已不存在。

必需:必须在 root.tsx 的 loader 中调用 rootAuthLoader。否则,嵌套路由的 loader 中调用 getAuth 会抛出异常。

心智模型

React Router v7/v8 使用中间件 + loader 管线。Clerk 会接入这两个层级:

  • 中间件(clerkMiddleware())——在每个请求上运行,将身份验证信息附加到上下文
  • rootAuthLoader——必须在 root.tsx 中调用,以将 Clerk 状态传递给客户端
  • getAuth(args)——在任何 loader/action 中调用,以获取当前用户
Request → clerkMiddleware() → rootAuthLoader → page loader → component
                 ↓                   ↓               ↓
           attaches auth      injects state     getAuth(args)
           to context         to response       reads context

在 Loaders 中进行身份验证

import { getAuth } from '@clerk/react-router/server'
import type { Route } from './+types/dashboard'

export async function loader(args: Route.LoaderArgs) {
  const { userId } = await getAuth(args)
  if (!userId) throw redirect('/sign-in')

  const data = await fetchUserData(userId)
  return { data }
}

在 Actions 中进行身份验证

import { getAuth } from '@clerk/react-router/server'

export async function action(args: Route.ActionArgs) {
  const { userId, orgId } = await getAuth(args)
  if (!userId) throw new Response('Unauthorized', { status: 401 })

  const formData = await args.request.formData()
  await saveData(userId, orgId, formData)
  return redirect('/dashboard')
}

客户端组件

import { useAuth, useUser } from '@clerk/react-router'

export function Profile() {
  const { userId, isSignedIn } = useAuth()
  const { user } = useUser()
  if (!isSignedIn) return null
  return <p>{user?.firstName}</p>
}

组织切换

import { OrganizationSwitcher } from '@clerk/react-router'

export function Nav() {
  return <OrganizationSwitcher afterSelectOrganizationUrl="/dashboard" />
}
export async function loader(args: Route.LoaderArgs) {
  const { userId, orgId } = await getAuth(args)
  if (!userId) throw redirect('/sign-in')
  if (!orgId) throw redirect('/select-org')

  return { data: await fetchOrgData(orgId) }
}

常见问题

现象原因修复方法
在 v8 开发环境中 SSR 时,ClerkProvider 抛出 useNavigate() may be used only in the context of a <Router>Vite 开发环境的 SSR 会将 @clerk/react-router 外部化,随后它加载 react-router 的生产构建,而应用使用开发构建——导致两个 Router 上下文。npm ls 中只有一个副本并不能排除该问题。在 vite.config.ts 中添加 ssr: { noExternal: ['@clerk/react-router'] }。切勿降级到 v7
构建错误:未导出 ClerkApp@clerk/react-router 中不存在 ClerkApp在 root.tsx 的默认导出中使用 <ClerkProvider loaderData={loaderData}>
clerkMiddleware() not detected缺少中间件(或在 v7 中缺少 v8_middleware future 标志)从根路由导出 middleware = [clerkMiddleware()];在 v7 中还要设置 future: { v8_middleware: true }
未知的 future 标志错误/警告(v8)升级后,react-router.config.ts 中仍保留 v8_middleware 标志删除 future.v8_middleware 条目——v8 中的中间件始终启用
getAuth 返回空的 userId未调用 rootAuthLoader在 root.tsx 的 loader 中调用 rootAuthLoader(args)
无限重定向循环重定向目标也受保护在保护检查中排除 /sign-in
action 中的 redirect 不起作用使用了 Response 而不是 throw redirect()使用来自 react-router 的 throw redirect('/path')

Import Map

WhatImport From
getAuth@clerk/react-router/server
rootAuthLoader@clerk/react-router/server
clerkMiddleware@clerk/react-router/server
ClerkProvider@clerk/react-router
useAuth, useUser@clerk/react-router
OrganizationSwitcher@clerk/react-router

See Also

  • clerk-setup - Initial Clerk install
  • clerk-custom-ui - Custom flows & appearance
  • clerk-orgs - B2B organizations

Docs

React Router SDK

评论

支持 Markdown