clerk-react-router-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact Router Patterns
React Router开发模式
SDK: v3+. Requires React Router v7.9+.
@clerk/react-routerSDK: v3+。要求React Router v7.9及以上版本。
@clerk/react-routerWhat Do You Need?
你需要什么?
| Task | Reference |
|---|---|
| Auth in loaders and actions | references/loaders-actions.md |
| Protected routes and redirects | references/protected-routes.md |
| SSR user data and session | references/ssr-auth.md |
| 任务 | 参考文档 |
|---|---|
| 加载器与操作函数中的鉴权 | references/loaders-actions.md |
| 受保护路由与重定向 | references/protected-routes.md |
| SSR用户数据与会话 | references/ssr-auth.md |
Mental Model
心智模型
React Router v7 uses a middleware + loader pipeline. Clerk plugs into both layers:
- Middleware () — runs on every request, attaches auth to context
clerkMiddleware() - — required in
rootAuthLoaderto pass Clerk state to the clientroot.tsx - — called inside any loader/action to get the current user
getAuth(args)
Request → clerkMiddleware() → rootAuthLoader → page loader → component
↓ ↓ ↓
attaches auth injects state getAuth(args)
to context to response reads contextReact Router v7采用中间件+加载器流水线架构。Clerk可接入这两个层级:
- 中间件 () — 对每个请求执行,将鉴权信息附加到上下文
clerkMiddleware() - — 需在
rootAuthLoader中定义,用于将Clerk状态传递给客户端root.tsx - — 可在任意加载器/操作函数内部调用,获取当前登录用户
getAuth(args)
Request → clerkMiddleware() → rootAuthLoader → page loader → component
↓ ↓ ↓
attaches auth injects state getAuth(args)
to context to response reads contextMinimal Setup
最小化配置
1. root.tsx
1. root.tsx
tsx
import { rootAuthLoader } from '@clerk/react-router/server'
import { ClerkApp } from '@clerk/react-router'
import type { Route } from './+types/root'
export async function loader(args: Route.LoaderArgs) {
return rootAuthLoader(args)
}
export default ClerkApp(function App() {
return <Outlet />
})tsx
import { rootAuthLoader } from '@clerk/react-router/server'
import { ClerkApp } from '@clerk/react-router'
import type { Route } from './+types/root'
export async function loader(args: Route.LoaderArgs) {
return rootAuthLoader(args)
}
export default ClerkApp(function App() {
return <Outlet />
})2. Middleware (root route or entry.server.ts)
2. 中间件(根路由或entry.server.ts)
tsx
import { clerkMiddleware } from '@clerk/react-router/server'
export const middleware = [clerkMiddleware()]Required:must be called inrootAuthLoader's loader. Without it,root.tsxthrows in nested loaders.getAuth
tsx
import { clerkMiddleware } from '@clerk/react-router/server'
export const middleware = [clerkMiddleware()]必填:必须在的加载器中调用root.tsx。如果缺少该配置,嵌套加载器中调用rootAuthLoader会抛出异常。getAuth
Auth in Loaders
加载器中的鉴权
tsx
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 }
}tsx
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 }
}Auth in Actions
操作函数中的鉴权
tsx
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')
}tsx
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')
}Client Components
客户端组件
tsx
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>
}tsx
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>
}Org Switching
组织切换
tsx
import { OrganizationSwitcher } from '@clerk/react-router'
export function Nav() {
return <OrganizationSwitcher afterSelectOrganizationUrl="/dashboard" />
}tsx
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) }
}tsx
import { OrganizationSwitcher } from '@clerk/react-router'
export function Nav() {
return <OrganizationSwitcher afterSelectOrganizationUrl="/dashboard" />
}tsx
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) }
}Common Pitfalls
常见问题
| Symptom | Cause | Fix |
|---|---|---|
| Missing middleware | Export |
| | Call |
| Infinite redirect loop | Redirect target is also protected | Exclude |
| Using | Use |
| 问题现象 | 原因 | 解决方案 |
|---|---|---|
| 缺少中间件配置 | 在根路由导出 |
| 未调用 | 在 |
| 无限重定向循环 | 重定向目标也处于受保护状态 | 将 |
| 使用了 | 使用 |
Import Map
导入映射表
| What | Import From |
|---|---|
| |
| |
| |
| |
| |
| |
| 导入项 | 导入来源 |
|---|---|
| |
| |
| |
| |
| |
| |
See Also
相关内容
- - Initial Clerk install
clerk-setup - - Custom flows & appearance
clerk-custom-ui - - B2B organizations
clerk-orgs
- - Clerk初始安装
clerk-setup - - 自定义流程与外观
clerk-custom-ui - - B2B组织管理
clerk-orgs