clerk-react-router-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React Router Patterns

React Router开发模式

SDK:
@clerk/react-router
v3+. Requires React Router v7.9+.
SDK:
@clerk/react-router
v3+。要求React Router v7.9及以上版本。

What Do You Need?

你需要什么?

TaskReference
Auth in loaders and actionsreferences/loaders-actions.md
Protected routes and redirectsreferences/protected-routes.md
SSR user data and sessionreferences/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 (
    clerkMiddleware()
    ) — runs on every request, attaches auth to context
  • rootAuthLoader
    — required in
    root.tsx
    to pass Clerk state to the client
  • getAuth(args)
    — called inside any loader/action to get the current user
Request → clerkMiddleware() → rootAuthLoader → page loader → component
                 ↓                   ↓               ↓
           attaches auth      injects state     getAuth(args)
           to context         to response       reads context
React Router v7采用中间件+加载器流水线架构。Clerk可接入这两个层级:
  • 中间件 (
    clerkMiddleware()
    ) — 对每个请求执行,将鉴权信息附加到上下文
  • rootAuthLoader
    — 需在
    root.tsx
    中定义,用于将Clerk状态传递给客户端
  • getAuth(args)
    — 可在任意加载器/操作函数内部调用,获取当前登录用户
Request → clerkMiddleware() → rootAuthLoader → page loader → component
                 ↓                   ↓               ↓
           attaches auth      injects state     getAuth(args)
           to context         to response       reads context

Minimal 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:
rootAuthLoader
must be called in
root.tsx
's loader. Without it,
getAuth
throws in nested loaders.
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

常见问题

SymptomCauseFix
clerkMiddleware() not detected
Missing middlewareExport
middleware = [clerkMiddleware()]
from root route
getAuth
returns empty userId
rootAuthLoader
not called
Call
rootAuthLoader(args)
in
root.tsx
loader
Infinite redirect loopRedirect target is also protectedExclude
/sign-in
from protection check
redirect
not working in action
Using
Response
instead of
throw redirect()
Use
throw redirect('/path')
from
react-router
问题现象原因解决方案
clerkMiddleware() not detected
缺少中间件配置在根路由导出
middleware = [clerkMiddleware()]
getAuth
返回空userId
未调用
rootAuthLoader
root.tsx
的加载器中调用
rootAuthLoader(args)
无限重定向循环重定向目标也处于受保护状态
/sign-in
排除在保护校验之外
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
ClerkApp
@clerk/react-router
useAuth
,
useUser
@clerk/react-router
OrganizationSwitcher
@clerk/react-router
导入项导入来源
getAuth
@clerk/react-router/server
rootAuthLoader
@clerk/react-router/server
clerkMiddleware
@clerk/react-router/server
ClerkApp
@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
  • clerk-setup
    - Clerk初始安装
  • clerk-custom-ui
    - 自定义流程与外观
  • clerk-orgs
    - B2B组织管理

Docs

文档