react-router

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React Router

React Router

Act as a senior React Router engineer reviewing code for correctness, performance, and best practices.
Review: $ARGUMENTS
以资深React Router工程师的身份审查代码的正确性、性能和最佳实践。
Review: $ARGUMENTS

Loaders

Loaders

  • Fetch all data in loaders, never in components with
    useEffect
    . Loaders run before render and eliminate loading spinners.
  • Use
    Promise.all
    for independent data fetches within a loader to avoid sequential waterfalls.
  • Use request-scoped caching (via context) so multiple loaders can call the same data function without duplicate requests.
  • Control revalidation with
    shouldRevalidate
    to skip unnecessary refetches. Use
    useRevalidator
    for polling/focus patterns.
  • Type loaders with
    Route.LoaderArgs
    and consume with
    useLoaderData<typeof loader>()
    .
  • Validate URL params early with zod or invariant — don't trust
    params
    to be well-formed.
  • Pass
    request.signal
    to fetch calls and database queries so they abort when the user navigates away.
  • Colocate data queries in
    queries.server.ts
    next to the route file.
  • 在加载器中获取所有数据,绝不要在组件中使用
    useEffect
    获取数据。加载器在渲染前运行,可消除加载动画。
  • 在加载器中对独立的数据获取使用
    Promise.all
    ,避免出现串行请求瀑布。
  • 使用请求作用域缓存(通过上下文),这样多个加载器可以调用同一个数据函数而不会产生重复请求。
  • 使用
    shouldRevalidate
    控制重新验证,跳过不必要的重新获取。使用
    useRevalidator
    实现轮询/聚焦模式。
  • 使用
    Route.LoaderArgs
    为加载器添加类型,并通过
    useLoaderData<typeof loader>()
    消费数据。
  • 尽早使用zod或invariant验证URL参数——不要假设
    params
    格式是正确的。
  • request.signal
    传递给fetch调用和数据库查询,这样当用户导航离开时请求会被中止。
  • 将数据查询放在路由文件旁的
    queries.server.ts
    中。

Actions

Actions

  • Validate all form data with zod schemas. Return validation errors with
    data({ errors }, { status: 400 })
    — don't throw for validation failures.
  • Use
    throw redirect("/path")
    after successful mutations to prevent resubmission (Post/Redirect/Get).
  • Use zod
    .transform()
    for input sanitization (trim, lowercase, parse numbers) during validation.
  • Use
    z.discriminatedUnion("intent", [...])
    to handle multiple actions in one route with type-safe intent matching.
  • Use
    clientAction
    for instant client-side validation before hitting the server.
  • Re-throw redirects and unknown errors in catch blocks — only catch expected error types.
  • 使用zod模式验证所有表单数据。通过
    data({ errors }, { status: 400 })
    返回验证错误——不要为验证失败抛出异常。
  • 成功执行变更后使用
    throw redirect("/path")
    ,防止重复提交(Post/Redirect/Get模式)。
  • 在验证期间使用zod的
    .transform()
    进行输入清理(修剪、转小写、解析数字)。
  • 使用
    z.discriminatedUnion("intent", [...])
    在单个路由中处理多个操作,实现类型安全的意图匹配。
  • 使用
    clientAction
    在请求服务器前进行即时客户端验证。
  • 在catch块中重新抛出重定向和未知错误——只捕获预期的错误类型。

Forms

Forms

  • Use
    useFetcher
    for in-place mutations (likes, toggles, inline edits) that shouldn't trigger navigation. Use
    <Form>
    when the mutation should navigate.
  • Show pending state with
    fetcher.state !== "idle"
    or
    useNavigation().state
    . Use
    useSpinDelay
    to avoid flicker.
  • Reset uncontrolled forms on success with
    formRef.current?.reset()
    in an effect.
  • Return field values from actions on validation error so inputs repopulate with
    defaultValue={actionData?.fields?.email}
    .
  • Add
    <HoneypotInputs />
    to public-facing forms for bot protection.
  • 对于不应触发导航的原地变更(点赞、切换、内联编辑),使用
    useFetcher
    。当变更应触发导航时,使用
    <Form>
  • 通过
    fetcher.state !== "idle"
    useNavigation().state
    显示等待状态。使用
    useSpinDelay
    避免闪烁。
  • 在成功时通过effect中的
    formRef.current?.reset()
    重置非受控表单。
  • 验证错误时从操作中返回字段值,这样输入框可以通过
    defaultValue={actionData?.fields?.email}
    重新填充内容。
  • 在面向公众的表单中添加
    <HoneypotInputs />
    以防止机器人提交。

Routing

Routing

  • Organize routes as folders with colocated
    queries.server.ts
    ,
    actions.server.ts
    ,
    route.tsx
    , and
    components/
    .
  • Use resource routes (no default export) for API-like endpoints. Name them
    api.<resource>.tsx
    .
  • Use dedicated action routes (
    actions.<noun>-<verb>.ts
    ) for reusable mutations consumed by multiple pages via
    useFetcher
    .
  • Name the default export
    Component
    in all route files.
  • Never import from other route files — import shared modules instead. Exception: import
    type { action }
    for
    useFetcher
    type inference.
  • Access parent route data with
    useRouteLoaderData
    in UI. In loaders, re-fetch (request-scoped caching prevents duplicate calls).
  • 将路由组织为文件夹,并存放在一起的有
    queries.server.ts
    actions.server.ts
    route.tsx
    components/
  • 对于类API的端点,使用资源路由(无默认导出)。将它们命名为
    api.<resource>.tsx
  • 对于可被多个页面通过
    useFetcher
    复用的变更操作,使用专用的操作路由(
    actions.<noun>-<verb>.ts
    )。
  • 在所有路由文件中,将默认导出命名为
    Component
  • 绝不要从其他路由文件导入——改为导入共享模块。例外情况:为了
    useFetcher
    的类型推断,导入
    type { action }
  • 在UI中使用
    useRouteLoaderData
    访问父路由数据。在加载器中,重新获取数据(请求作用域缓存可防止重复调用)。

Middleware

Middleware

  • Authenticate in middleware, authorize in each loader/action. Keep auth checks close to data access.
  • Store session in middleware so loaders/actions get a single instance per request.
  • Use
    AsyncLocalStorage
    for request-scoped context accessible without passing args through every function.
  • Add
    Server-Timing
    headers in middleware for performance observability.
  • Generate a request ID in middleware for log correlation across the request lifecycle.
  • 在中间件中进行身份验证,在每个加载器/操作中进行授权。将权限检查放在靠近数据访问的位置。
  • 在中间件中存储会话,这样加载器/操作在每个请求中只会获取一个实例。
  • 使用
    AsyncLocalStorage
    实现请求作用域上下文,无需通过每个函数传递参数即可访问。
  • 在中间件中添加
    Server-Timing
    头,用于性能可观测性。
  • 在中间件中生成请求ID,用于在请求生命周期内关联日志。

Security

Security

  • Protect mutations with CSRF tokens or verify
    Sec-Fetch-Site
    headers to reject cross-site requests.
  • Sanitize user-driven redirect URLs with
    safeRedirect(redirectTo, "/")
    — never redirect to arbitrary user input.
  • Apply CORS headers only to API resource routes that need cross-origin access. Use specific origins, not wildcards.
  • Validate cookie payloads with schemas using typed cookies.
  • Use
    prefetch="intent"
    on
    <Link>
    for faster navigation — preloads data on hover/focus.
  • 使用CSRF令牌或验证
    Sec-Fetch-Site
    头来保护变更操作,拒绝跨站点请求。
  • 使用
    safeRedirect(redirectTo, "/")
    清理用户驱动的重定向URL——绝不要重定向到任意用户输入的地址。
  • 仅对需要跨域访问的API资源路由应用CORS头。使用特定的源,不要使用通配符。
  • 使用类型化Cookie通过模式验证Cookie负载。
  • <Link>
    上使用
    prefetch="intent"
    实现更快的导航——在悬停/聚焦时预加载数据。

Error Handling

Error Handling

  • Export
    ErrorBoundary
    from every route with data fetching. Use
    isRouteErrorResponse
    to distinguish HTTP errors from unexpected exceptions.
  • In layout routes, make
    ErrorBoundary
    layout-aware so errors render within the app shell.
  • Use
    <Suspense>
    with
    <Await resolve={promise}>
    for streamed loader data — return promises from
    data()
    and they auto-stream.
  • 每个带有数据获取的路由都导出
    ErrorBoundary
    。使用
    isRouteErrorResponse
    区分HTTP错误和意外异常。
  • 在布局路由中,使
    ErrorBoundary
    支持布局感知,这样错误会在应用外壳内渲染。
  • 对流式加载器数据使用
    <Suspense>
    <Await resolve={promise}>
    ——从
    data()
    返回Promise,它们会自动流式传输。