更新日志.md
本页内容

React Router 发布版本

此页面列出了自 v6.0.0 以来 React Router 的所有发布版本/发布说明。对于 v6 之前的版本,请参阅 Github 发布页面

我们在此文件中管理发布说明,而不是在分页的 Github 发布页面上,原因有二:

  • Github UI 中的分页意味着您无法轻松地一次性搜索大范围版本的发布说明。
  • 分页的 Github 界面在列表视图中也会截断较长的发布说明,并且没有任何提示,您需要点击进入详细视图才能看到完整的发布说明。
目录

v7.8.0

日期:2025-08-07

变更内容

统一命名的 loaderData

是否曾注意到框架提供给你的 loader 数据值存在差异?比如,在你的组件 props 中我们称之为 loaderData,但在你的匹配项中却是 match.data?是的,我们也注意到了——以及一些眼尖的 React Router 用户在一份提案中提出了这个问题。我们已经在一些遗留的地方添加了新的 loaderData 字段,与现有的 data 字段并存,以与新的 Route.* API 中使用的 loaderData 命名保持一致。

对中间件 API 的改进/修复(不稳定)

7.8.0 中最大的一组变更是针对 unstable_middleware API 的,因为我们正朝着稳定这些 API 的方向迈进。如果您已经采纳了中间件 API 进行早期测试,请仔细阅读下面的中间件变更。我们希望尽快稳定这些 API,所以请就 API 当前的状态向我们提供任何反馈!

次要变更

  • react-router - 向 LinksPrefetchPageLinks 添加 nonce 属性 (#14048)
  • react-router - 在现有的 data 参数/属性旁边添加 loaderData 参数/属性,以在整个框架中提供 loaderDataactionData 之间的一致性和清晰度 (#14047)
    • 更新的类型:Route.MetaArgs, Route.MetaMatch, MetaArgs, MetaMatch, Route.ComponentProps.matches, UIMatch
    • 已向现有的 data 属性添加了 @deprecated 警告,以引导用户使用新的 loaderData 属性,为在未来的主要版本中移除 data 属性做准备。

补丁变更

  • react-router - 在 fetcher.submit 重新验证期间进行导航时,防止出现 "Did not find corresponding fetcher result" 控制台错误 (#14114)

  • react-router - 将懒加载路由发现清单 URL 的生成切换为使用独立的 URLSearchParams 实例,而不是 URL.searchParams,以避免在 Chrome 中出现严重的性能瓶颈 (#14084)

  • react-router - 调整内部 RSC 对 React.use 的使用,以避免在使用 React 18 时出现 Webpack 编译错误 (#14113)

  • react-router - 从 TypeScript 声明文件中移除对 @types/node 的依赖 (#14059)

  • react-router - 修复 UIMatch 的类型,以反映 loaderData/data 属性可能是 undefined (#12206)

    • 当渲染 ErrorBoundary 时,并非所有活动匹配项都有可用的 loader 数据,因为它可能是它们的 loader 抛出错误触发了边界。

    • UIMatch.data 类型没有正确处理这种情况,并且总是反映数据的存在,导致在渲染 ErrorBoundary 时出现意外的运行时错误。

    • ⚠️ 这可能会导致您的代码中出现一些未受保护的 match.data 访问的类型错误 - 在这些情况下,您应该适当地为 undefined 值进行保护。

      // app/root.tsx
      export function loader() {
        someFunctionThatThrows(); // ❌ Throws an Error
        return { title: "My Title" };
      }
      
      export function Layout({ children }: { children: React.ReactNode }) {
        let matches = useMatches();
        let rootMatch = matches[0] as UIMatch<Awaited<ReturnType<typeof loader>>>;
        //  ^ rootMatch.data is currently incorrectly typed here, so TypeScript does
        //    not complain if you do the following which throws an error at runtime:
        let { title } = rootMatch.data; // 💥
      
        return <html>...</html>;
      }
      
  • @react-router/dev - 修复 Vite 插件中没有 mkdir 的重命名操作 (#14105)

不稳定变更

⚠️ 不稳定功能不建议在生产环境中使用

RSC

  • react-router - 修复数据模式问题:当 shouldRevalidate 返回 false 时,返回错误的路由会被替换为 <Outlet /> (#14071)
  • react-router - 代理来自操作的服务器操作副作用重定向,用于文档和 callServer 请求 (#14131)

中间件

  • react-router - 更改 RouterProviderHydratedRouterunstable_RSCHydratedRouter 上的 unstable_getContext 签名,使其返回一个 unstable_RouterContextProvider 实例,而不是用于在内部构造实例的 Map (#14097)

    • 更多信息请参阅文档
    • ⚠️ 如果您已经采纳了 unstable_getContext 属性,这是一个破坏性变更。
  • react-router - 即使没有 loader 存在,也在客户端导航上运行客户端中间件 (#14106)

  • react-router - 将内部中间件实现转换为使用新的 unstable_generateMiddlewareResponse API (#14103)

  • react-router - 确保在启用中间件的情况下,资源路由错误通过 handleError 处理 (#14078)

  • react-router - 如果 next 未被调用,则传播从服务器中间件返回的 Response (#14093)

  • react-router - 允许服务器中间件返回 data() 值,这些值将被转换为 Response (#14093, #14128)

  • react-router - 更新中间件错误处理,使 next 函数永不抛出错误,而是在适当的 ErrorBoundary 处理任何中间件错误,并通过祖先 next 函数返回 Response (#14118)

    • 更多信息请参阅错误处理文档
    • ⚠️ 这改变了现有功能,所以如果您当前在 try/catch 中包装 next 调用,您应该可以移除它们。
  • react-router - 将 next 之前的客户端中间件错误冒泡到适当的祖先错误边界 (#14138)

  • react-router - 当中间件启用时,将 context 参数设为只读 (Readonly<unstable_RouterContextProvider>),这样 TypeScript 将不允许您在 loader、action 或中间件中向其写入任意字段。 (#14097)

  • react-router - 重命名并更改 staticHandler.query/staticHandler.queryRouteunstable_respond API 的签名/功能 (#14103)

    • 这仅影响在非框架模式 SSR 期间使用 createStaticHandler() 进行手动数据加载的用户。

    • 该 API 已重命名为 unstable_generateMiddlewareResponse 以提高清晰度。

    • 主要的功能变化是,我们现在将一个 query/queryRoute 函数作为参数传递,您可以在回调函数中执行 loader/action,从而完全访问预处理和错误处理,而不是在调用 unstable_respond 之前运行 loader/action 并将结果交给您。

    • API 的 query 版本现在具有 (query: (r: Request) => Promise<StaticHandlerContext | Response>) => Promise<Response> 的签名。

    • API 的 queryRoute 版本现在具有 (queryRoute: (r: Request) => Promise<Response>) => Promise<Response> 的签名。

    • 这允许更高级的用法,例如在调用 query 之前/之后运行逻辑,以及直接处理从 query 抛出的错误。

    • ⚠️ 如果您已采纳 staticHandlerunstable_respond API,这是一个破坏性变更。

      let response = await staticHandler.query(request, {
        requestContext: new unstable_RouterContextProvider(),
        async unstable_generateMiddlewareResponse(query) {
          try {
            // At this point we've run middleware top-down so we need to call the
            // handlers and generate the Response to bubble back up the middleware
            let result = await query(request);
            if (isResponse(result)) {
              return result; // Redirects, etc.
            }
            return await generateHtmlResponse(result);
          } catch (error: unknown) {
            return generateErrorResponse(error);
          }
        },
      });
      
  • @react-router/{architect,cloudflare,express,node} - 当 future.unstable_middleware 启用时,更改 getLoadContext 签名 (type GetLoadContextFunction),使其返回一个 unstable_RouterContextProvider 实例,而不是用于在内部构造实例的 Map (#14097)

    • 这也移除了 type unstable_InitialContext 导出。
    • 更多信息请参阅中间件 `getLoadContext` 文档
    • ⚠️ 如果您已采纳中间件并使用带有 getLoadContext 函数的自定义服务器,这是一个破坏性变更。

按包分类的变更

完整更新日志: v7.7.1...v7.8.0

v7.7.1

日期:2025-07-24

补丁变更

  • @react-router/dev - 在运行 react-router reveal --no-typescript 时,更新到 Prettier v3 进行格式化 (#14049)

不稳定变更

⚠️ 不稳定功能不建议在生产环境中使用

  • react-router - RSC 数据模式:修复当 shouldRevalidate 返回 false 时,有错误的路由没有被强制重新验证的 bug (#14026)
  • react-router - RSC 数据模式:修复当错误边界被渲染时出现的 `Matched leaf route at location "/..." does not have an element or Component` 警告 (#14021)

完整更新日志: v7.7.0...v7.7.1

v7.7.0

日期:2025-07-16

变更内容

不稳定的 RSC API

我们很高兴通过以下新 API 在数据模式中引入对 RSC 的实验性支持:

更多信息,请查看博客文章RSC 文档

次要变更

  • create-react-router - 添加 Deno 作为支持和可检测的包管理器。请注意,此检测仅适用于 Deno 2.0.5 及以上版本。如果您使用的是旧版 Deno,则必须将 --package-manager CLI 标志设置为 deno。 (#12327)
  • @react-router/remix-config-routes-adapter - 与 DefineRoutesFunction 一同导出 DefineRouteFunction 类型 (#13945)

补丁变更

  • react-router - 在验证 cookie 签名时处理 InvalidCharacterError (#13847)

  • react-router - 将 searchParams 的副本传递给 setSearchParams 回调函数,以避免内部 searchParams 实例的突变 (#12784)

    • 如果您在导航被阻塞时突变当前有状态的 searchParams,这会导致错误,因为内部实例会与 useLocation().search 不同步。
  • react-router - 在 turbo-stream v2 分支中支持无效的 Date (#13684)

  • react-router - 在框架模式下,在初始渲染后清除开发环境中的关键 CSS (#13872, #13995)

  • react-router - 从 patchRoutesOnNavigationpath 参数中剥离搜索参数,用于 fetcher 调用 (#13911)

  • react-router - 跳过 useRevalidator() 调用时的滚动恢复,因为它们不是新位置 (#13671)

  • react-router - 在 ssr 设置为 false 的情况下,支持预渲染配置中未编码的 UTF-8 路由 (#13699)

  • react-router - 如果 URL 哈希不是有效的 URI 组件,则不抛出错误 (#13247)

  • react-router - 从单一获取响应中移除 Content-Length 标头 (#13902)

  • react-router - 修复了在引入中间件功能时 createRoutesStub 出现的回归问题 (#13946)

    • 作为这项工作的一部分,我们更改了签名以与新的中间件 API 对齐,但没有使其与之前的 AppLoadContext API 向后兼容。

    • 这使得如果您选择使用中间件和更新的 context 类型,createRoutesStub 可以工作,但对于尚未选择使用中间件的用户,createRoutesStub 出现了问题。

    • 我们已经恢复了这一变更,并以一种两种用户都可以利用的方式重新实现了它。

    • ⚠️ 如果您已经采用了不稳定的中间件功能,并且正在使用更新后的 API 的 `createRoutesStub`,这可能是一个破坏性的 bug。

      // If you have not opted into middleware, the old API should work again
      let context: AppLoadContext = {
        /*...*/
      };
      let Stub = createRoutesStub(routes, context);
      
      // If you have opted into middleware, you should now pass an instantiated
      // `unstable_routerContextProvider` instead of a `getContext` factory function.
      let context = new unstable_RouterContextProvider();
      context.set(SomeContext, someValue);
      let Stub = createRoutesStub(routes, context);
      
  • @react-router/dev - 更新 vite-node^3.2.2 以支持 Vite 7 (#13781)

  • @react-router/dev - 在开发模式下正确处理 https 协议 (#13746)

  • @react-router/dev - 修复当 Vite 的 build.cssCodeSplit 选项被禁用时样式丢失的问题 (#13943)

  • @react-router/dev - 允许路由配置文件使用 .mts.mjs 扩展名 (#13931)

  • @react-router/dev - 修复当 cwd 与项目根目录不同时预渲染文件的位置问题 (#13824)

  • @react-router/dev - 在构建期间找不到块时,改进块错误日志记录 (#13799)

  • @react-router/dev - 修复了错误配置的 externalConditions,该配置为外部模块启用了 module 条件,并破坏了某些包(如 Emotion)的构建 (#13871)

不稳定变更

⚠️ 不稳定功能不建议在生产环境中使用

  • 为数据模式添加不稳定的 RSC 支持 (#13700)

按包分类的变更

完整更新日志: v7.6.3...v7.7.0

v7.6.3

日期:2025-06-27

补丁变更

  • react-router - 不要为 useRouteLoaderData<typeof clientLoader> 序列化类型 (#13752)

    • 为了让类型区分 clientLoaderserverLoader,您必须为 clientLoader 参数添加注解。

      //                                   👇 annotation required to skip serializing types
      export function clientLoader({}: Route.ClientLoaderArgs) {
        return { fn: () => "earth" };
      }
      
      function SomeComponent() {
        const data = useRouteLoaderData<typeof clientLoader>("routes/this-route");
        const planet = data?.fn() ?? "world";
        return <h1>Hello, {planet}!</h1>;
      }
      
  • @react-router/cloudflare - 从 peerDependencies 中移除 tsup (#13757)

  • @react-router/dev - 添加 Vite 7 支持 (#13748)

  • @react-router/dev - 当提供了自定义的 entry.server.(j|t)sx 文件时,跳过 package.json 解析检查 (#13744)

  • @react-router/dev - 为路由 id 不为 'root' 的情况添加验证 (#13792)

  • @react-router/fs-routes @react-router/remix-config-routes-adapter - 使用 replaceAll 来规范化 Windows 文件系统斜杠 (#13738)

  • @react-router/node - 移除旧的 "install" 包导出 (#13762)

完整更新日志: v7.6.2...v7.6.3

v7.6.2

日期:2025-06-03

补丁变更

  • create-react-router - 更新 tar-fs (#13675)

  • react-router - (内部) 轻微重构内部 headers() 函数处理,以用于 RSC (#13639)

  • react-router @react-router/dev - 通过将路由模块组件属性逻辑从 Vite 插件移至 react-router,避免在框架模式下产生额外的 with-props 块 (#13650)

  • @react-router/dev - 当启用 future.unstable_viteEnvironmentApi 并配置了绝对的 Vite base 时,确保在开发期间正确处理关键 CSS (#13598)

  • @react-router/dev - 更新 vite-node (#13673)

  • @react-router/dev - 修复非 {.js,.jsx,.ts,.tsx} 路由(如 .mdx)的类型生成问题 (#12453)

  • @react-router/dev - 修复可选动态参数的 href 类型问题 (#13725)

    7.6.1 引入了对可选静态段的 href 修复,但这些修复导致了 7.6.0 中可选动态参数工作方式的回归。

    // 7.6.0
    href("/users/:id?"); // ✅
    href("/users/:id?", { id: 1 }); // ✅
    
    // 7.6.1
    href("/users/:id?"); // ❌
    href("/users/:id?", { id: 1 }); // ❌
    

    现在,可选静态段会扩展为不同的 href 路径,但可选动态参数则不会。这样,href 就可以明确地引用一个确切的 URL 路径,同时将路径选项的数量保持在最低限度。

    // 7.6.2
    
    // path: /users/:id?/edit?
    href("
    //    ^ suggestions when cursor is here:
    //
    //    /users/:id?
    //    /users/:id?/edit
    

    此外,您可以从组件属性传递 params,而无需手动进行类型收窄。

    declare const params: { id?: number };
    
    // 7.6.0
    href("/users/:id?", params);
    
    // 7.6.1
    href("/users/:id?", params); // ❌
    "id" in params ? href("/users/:id", params) : href("/users"); // works... but is annoying
    
    // 7.6.2
    href("/users/:id?", params); // restores behavior of 7.6.0
    

完整更新日志: v7.6.1...v7.6.2

v7.6.1

日期:2025-05-25

补丁变更

  • react-router - 部分还原在 7.1.4 中为减少对 matchRoutes 调用而添加的优化,因为它暴露了其他问题 (#13562)

  • react-router - 更新 Route.MetaArgs 以反映 data 可能为 undefined 的情况 (#13563)

    • 这主要适用于路由 loader 向其自身的 ErrorBoundary 抛出错误的情况,但它也出现在 404 错误的情况下,该错误会渲染根 ErrorBoundary/meta,但由于没有路由匹配,根 loader 并未运行。
  • react-router - 避免在懒加载路由发现被导航中断时,初始 fetcher 执行 404 错误 (#13564)

  • react-router - 正确地用 href 替换通配符 * (#13593)

    • href("/products/*", { "*": "/1/edit" }); // -> /products/1/edit
  • @react-router/architect - 将 @architect/functions^5.2.0 更新至 ^7.0.0 (#13556)

  • @react-router/dev - 防止对 app/ 目录之外的路由文件进行类型生成 (#12996)

  • @react-router/dev - 在清理服务器构建中的资源时,向 build 命令输出添加额外的日志记录 (#13547)

  • @react-router/dev - 当 Vite 配置中启用了 build.ssrEmitAssets 时,不要从服务器构建中清理资源 (#13547)

  • @react-router/dev - 修复当同一路由在多个路径中使用时的类型生成问题 (#13574)

    • 例如,routes/route.tsx 在这里被用于 4 个不同的路径。

      import { type RouteConfig, route } from "@react-router/dev/routes";
      export default [
        route("base/:base", "routes/base.tsx", [
          route("home/:home", "routes/route.tsx", { id: "home" }),
          route("changelog/:changelog", "routes/route.tsx", { id: "changelog" }),
          route("splat/*", "routes/route.tsx", { id: "splat" }),
        ]),
        route("other/:other", "routes/route.tsx", { id: "other" }),
      ] satisfies RouteConfig;
      
    • 以前,类型生成会任意选择其中一个路径作为“获胜者”,并基于该路径为路由模块生成类型。

    • 现在,类型生成会根据需要为同一路由文件的备用路径创建联合类型。

  • @react-router/dev - 更好的 params 类型 (#13543)

    • 例如:

      // routes.ts
      import { type RouteConfig, route } from "@react-router/dev/routes";
      
      export default [
        route("parent/:p", "routes/parent.tsx", [
          route("route/:r", "routes/route.tsx", [
            route("child1/:c1a/:c1b", "routes/child1.tsx"),
            route("child2/:c2a/:c2b", "routes/child2.tsx"),
          ]),
        ]),
      ] satisfies RouteConfig;
      
    • 以前,routes/routeparams 被计算为 { p: string, r: string }

    • 这错误地忽略了可能来自子路由的参数。

    • 如果访问 /parent/1/route/2/child1/3/4,传递给 routes/route 的实际参数类型将是 { p: string, r: string, c1a: string, c1b: string }

    • 现在,params 能够感知子路由,并且自动完成将包括子参数作为可选参数。

      params.|
      //     ^ cursor is here and you ask for autocompletion
      // p: string
      // r: string
      // c1a?: string
      // c1b?: string
      // c2a?: string
      // c2b?: string
      
    • 您还可以缩小 params 的类型,因为它被实现为包含 routes/route 的每个页面的参数的规范化联合类型。

      if (typeof params.c1a === 'string') {
        params.|
        //     ^ cursor is here and you ask for autocompletion
        // p: string
        // r: string
        // c1a: string
        // c1b: string
      }
      
  • @react-router/dev - 修复可选段的 href (#13595)

    • 类型生成现在会将带有可选段的路径扩展为其对应的非可选路径。

    • 例如,路径 /user/:id? 被扩展为 /user/user/:id,以更紧密地模拟可访问的 URL。

    • 然后,href 使用这些扩展的(非可选)路径来为您的应用程序构建类型安全的路径。

      // original: /user/:id?
      // expanded: /user & /user/:id
      href("/user"); // ✅
      href("/user/:id", { id: 1 }); // ✅
      
    • 对于静态可选路径,这变得更加重要,因为之前没有好的方法来指示是否应在结果路径中包含可选段。

      // original: /products/:id/detail?
      
      // before
      href("/products/:id/detail?"); // ❌ How can we tell `href` to include or omit `detail?` segment with a complex API?
      
      // now
      // expanded: /products/:id & /products/:id/detail
      href("/product/:id"); // ✅
      href("/product/:id/detail"); // ✅
      

不稳定变更

⚠️ 不稳定功能不建议在生产环境中使用

  • @react-router/dev - 将内部的 react-router/route-module 导出重命名为 react-router/internal (#13543)
  • @react-router/dev - 从生成的 +types/* 文件中移除了 Info 导出 (#13543)
  • @react-router/dev - 在生成 SRI 清单时,跨 Node 版本规范化 dirent 条目路径 (#13591)

完整更新日志: v7.6.0...v7.6.1

v7.6.0

日期:2025-05-08

变更内容

routeDiscovery 配置选项

我们在 7.6.0 中添加了一个新的配置选项,让您能更好地控制懒加载路由发现功能。如果您在同一台服务器上运行多个 RR 应用程序,现在可以配置 /__manifest 路径;或者,如果您的应用程序足够小且不需要该功能,您也可以完全禁用它。

// react-router.config.ts

export default {
  // You can modify the manifest path used:
  routeDiscovery: { mode: "lazy", manifestPath: "/custom-manifest" }

  // Or you can disable this feature entirely and include all routes in the
  // manifest on initial document load:
  routeDiscovery: { mode: "initial" }

  // If you don't specify anything, the default config is as follows, which enables
  // Lazy Route Discovery and makes manifest requests to the `/__manifest` path:
  // routeDiscovery: { mode: "lazy", manifestPath: "/__manifest" }
} satisfies Config;

未来标志的自动类型

一些未来标志会改变 React Router 中类型的工作方式。以前,您必须记住手动选择加入新类型。例如,对于 future.unstable_middleware

// react-router.config.ts

// Step 1: Enable middleware
export default {
  future: {
    unstable_middleware: true,
  },
};

// Step 2: Enable middleware types
declare module "react-router" {
  interface Future {
    unstable_middleware: true; // 👈 Enable middleware types
  }
}

保持运行时未来标志与这些标志的类型同步是您的责任。这既令人困惑又容易出错。

现在,React Router 将自动为未来标志启用类型。这意味着您只需要指定运行时未来标志。

// react-router.config.ts

// Step 1: Enable middleware
export default {
  future: {
    unstable_middleware: true,
  },
};

// No step 2! That's it!

在幕后,React Router 会将相应的 declare module 生成到 .react-router/types 中。目前这是在 .react-router/types/+register.ts 中完成的,但这是一个实现细节,将来可能会改变。

次要变更

  • react-router - 在 react-router.config.ts 中添加了一个新的 routeDiscovery 选项,用于配置懒加载路由发现行为 (#13451)

  • react-router - 在 createRoutesStub 中添加对路由组件属性的支持 (#13528)

    • 这允许您使用属性而不是钩子来对路由组件进行单元测试。

      let RoutesStub = createRoutesStub([
        {
          path: "/",
          Component({ loaderData }) {
            let data = loaderData as { message: string };
            return <pre data-testid="data">Message: {data.message}</pre>;
          },
          loader() {
            return { message: "hello" };
          },
        },
      ]);
      
      render(<RoutesStub />);
      
      await waitFor(() => screen.findByText("Message: hello"));
      
  • @react-router/dev - 未来标志的自动类型 (#13506)

补丁变更

您可能会注意到这个列表比平时要长一些!团队上周埋头苦干,修复了大量 bug,以减少自 v7 发布以来激增的问题数量。

  • react-router - 修复 react-routerNodeNext 下的模块增强问题 (#13498)
  • react-router - 不要在 react-router/dom 的 CJS 导出中捆绑 react-router (#13497)
  • react-router - 修复了一个 bug,即如果一个正在重新验证的 loader 进行了重定向,一个正在提交的 fetcher 会卡在 loading 状态 (#12873)
  • react-router - 修复如果服务器 loader 返回 undefined 时的水合错误 (#13496)
  • react-router - 修复数据模式下初始加载 404 的场景 (#13500)
  • react-router - 稳定 useRevalidatorrevalidate 函数 (#13542)
  • react-router - 如果 clientAction 在框架模式下抛出 data() 结果,则保留状态码 (#13522)
  • react-router - 增强对路径中前导双斜杠的防御,以避免 URL 构造函数抛出 Invalid URL 错误 (#13510)
    • 请注意,我们不会清理/规范化这些路径——我们只检测它们,以便避免 new URL("//", window.location.origin) 抛出的错误。
  • react-router - 移除 navigator.connection.saveDataNavigator 声明,以避免在用户代码中干扰除 saveData 之外的任何其他类型 (#13512)
  • react-router - 修复对于最后一个 URL 段是动态参数的路由,在 .data 请求中 handleErrorparams 值不正确的问题 (#13481)
  • react-router - 在懒加载路由发现中检测到清单版本不匹配时,不再在重新加载前触发 ErrorBoundary 界面 (#13480)
  • react-router - 内联 turbo-stream@2.4.1 依赖项,并修复 Map/Set 实例的解码顺序问题 (#13518)
  • react-router - 仅在开发模式下渲染开发警告 (#13461)
  • react-router - 在 dataStrategy 请求被中止时,短路后续处理 (#13521)
    • 此修复解决了形式为 Cannot read properties of undefined (reading 'result') 的非用户可见的控制台错误。
  • @react-router/dev - 支持项目根目录中没有 package.json,只要它存在于父目录中即可 (#13472)
  • @react-router/dev - 当通过 CLI 的 --config/-c 标志提供自定义 Vite 配置文件路径时,如果未明确提供项目根目录,则默认为包含 Vite 配置文件的目录 (#13472)
  • @react-router/dev - 在 routes.ts 上下文中,确保 import.meta.env.MODE 能够遵循 --mode 标志 (#13485)
    • 以前,在 routes.ts 上下文中的 import.meta.env.MODE 对于 devtypegen --watch 命令总是为 "development",否则解析为 "production"。这些默认值仍然有效,但如果提供了 --mode 标志,现在它将具有更高的优先级。
  • @react-router/dev - 确保 CLI 命令中项目根目录解析逻辑的一致性 (#13472)
  • @react-router/dev - 当使用 vite-node 执行 react-router.config.tsroutes.ts 时,确保忽略 PostCSS 配置文件 (#13489)
  • @react-router/dev - 在开发期间提取关键 CSS 时,确保从客户端环境加载,以避免与那些对 SSR 环境处理方式不同的插件产生问题 (#13503)
  • @react-router/dev - 修复在使用 HTTPS 的开发模式下出现的“Status message is not supported by HTTP/2”错误 (#13460)
  • @react-router/dev - 在开发过程中创建或删除 react-router.config.ts 时更新配置 (#12319)
  • @react-router/dev - 在 Vite 构建开始前,跳过不必要的 routes.ts 评估 (#13513)
  • @react-router/dev - 修复由生成的类型引起的 TS2300: Duplicate identifier(重复标识符)错误 (#13499)
  • 以前,具有相同完整路径的路由会导致在为 href 生成的类型(.react-router/types/+register.ts)中出现重复条目,从而导致类型检查错误。

不稳定变更

⚠️ 不稳定功能不建议在生产环境中使用

  • react-router - 修复了在中间件用例中错误冒泡的一些错误 (#13538)
  • @react-router/dev - 当启用 future.unstable_viteEnvironmentApi 时,确保在未配置 environments.client.build.assetsDir 的情况下,Vite 配置中的 build.assetsDir 得到遵循 (#13491)

各软件包的变更

完整变更日志: v7.5.3...v7.6.0

v7.5.3

日期: 2025-04-28

补丁变更

  • react-router - 修复了冒泡的 action 错误会导致在处理该错误的 ErrorBoundary 路由中清除 loaderData 的错误 (#13476)
  • react-router - 处理来自 clientLoader.hydrate 初始加载执行的重定向 (#13477)

完整变更日志: v7.5.2...v7.5.3

v7.5.2

日期: 2025-04-24

安全公告

修复了 2 个安全漏洞,这些漏洞可能因发送专用于构建时 SPA 模式和预渲染的特定头信息而导致缓存中毒攻击(GHSA-f46r-rw29-r322, GHSA-cpj6-fhp6-mr6j)。

补丁变更

  • react-router - 调整通过头信息实现预渲染/SPA 模式的方法 (#13453)
  • react-router - 更新单次获取(Single Fetch)以处理 Remix v2 中用于 ?_data 请求的 204 重定向 (#13364)
    • 这使得应用程序可以像在实现单次获取之前的 Remix v2 中那样,从 React Router 范围之外(例如,express/hono 中间件)触发对 .data 请求的重定向。
    • 这是一个应急方案——推荐的处理方式是从根路由中间件进行重定向。
    • 要使用此功能,您可以从一个 .data 请求中返回如下响应:
      • 设置 204 状态码
      • 设置一个 X-Remix-Redirect: <new-location> 头信息
      • 可选地,设置 X-Remix-Replace: trueX-Remix-Reload-Document: true 头信息以模拟 replace()/redirectDocument() 功能
    • ⚠️ 请注意,这些响应依赖于实现细节,这些细节可能会在没有 SemVer 主要版本发布的情况下发生变化,建议您为应用程序设置集成测试,以确认此功能在每次 React Router 未来升级时都能正常工作。

完整变更日志: v7.5.1...v7.5.2

v7.5.1

日期: 2025-04-17

补丁变更

  • react-router - 当使用基于对象的 route.lazy API 时,HydrateFallbackhydrateFallbackElement 属性在水合后懒加载路由时现在会被跳过 (#13376)

    • 如果您将这些属性的代码移到一个单独的文件中,由于水合属性已经未使用(如果路由在水合期间不存在),您可以完全避免下载它们。例如:

      createBrowserRouter([
        {
          path: "/show/:showId",
          lazy: {
            loader: async () => (await import("./show.loader.js")).loader,
            Component: async () =>
              (await import("./show.component.js")).Component,
            HydrateFallback: async () =>
              (await import("./show.hydrate-fallback.js")).HydrateFallback,
          },
        },
      ]);
      
  • react-router - 修复了单次获取的一个错误,该错误导致在向上导航到重用的父路由时不会发出重新验证请求 (#13253)

  • react-router - 在使用 ssr:false + prerender 配置时,当参数值改变时,正确地重新验证预渲染的路径 (#13380)

  • react-router - 修复了当 loader 返回重定向时的预渲染问题 (#13365)

  • react-router - 如果路由没有 loader,不要自动向 staticHandler.query()context.loaderData 添加 null (#13223)

    • 这是 Remix v2 的一个实现细节,无意中保留在了 React Router v7 中。
    • 既然我们允许 loader 返回 undefined,我们之前 loaderData[routeId] !== undefined 的检查已经不再足够,并已更改为 routeId in loaderData 的检查——这些 null 值可能会对这个新检查造成问题。
    • ⚠️ 如果您正在使用 createStaticHandler()/<StaticRouterProvider> 进行手动 SSR,并使用 context.loaderData 来控制客户端上的 <RouterProvider> 水合行为,这可能对您来说是一个“破坏性错误修复”。

不稳定变更

⚠️ 不稳定功能不建议在生产环境中使用

  • react-router - 当 getLoadContext 未更新以返回一个 Map 时,添加了更好的错误消息 (#13242)
  • react-router - 当启用中间件时,更新 LoaderFunctionArgs/ActionFunctionArgs 的上下文类型 (#13381)
  • react-router - 向 dataStrategy 添加一个新的 unstable_runClientMiddleware 参数,以在自定义 dataStrategy 实现中启用中间件执行 (#13395)
  • react-router - 在 dataStrategy 中增加了对新的 unstable_shouldCallHandler/unstable_shouldRevalidateArgs API 的支持 (#13253)

完整变更日志: v7.5.0...v7.5.1

v7.5.0

日期: 2025-04-04

新功能

route.lazy 对象 API

我们引入了一个新的 route.lazy API,它让您对路由属性的懒加载有更精细的控制,这是使用 route.lazy() 函数签名无法实现的。这对于框架模式和性能关键的库模式应用程序非常有用。

createBrowserRouter([
  {
    path: "/show/:showId",
    lazy: {
      loader: async () => (await import("./show.loader.js")).loader,
      action: async () => (await import("./show.action.js")).action,
      Component: async () => (await import("./show.component.js")).Component,
    },
  },
]);

⚠️ 如果您采用了 route.unstable_lazyMiddleware API,这将是一个破坏性变更,因为它已被移除,取而代之的是 route.lazy.unstable_middleware。更多信息请参见下面的“不稳定变更”部分。

次要变更

  • react-router - 为 route.lazy 添加了基于对象的细粒度 API,以支持单个路由属性的懒加载 (#13294)

补丁变更

  • @react-router/dev - 更新可选的 wrangler 对等依赖项范围,以支持 wrangler v4 (#13258)
  • @react-router/dev - 在子编译器中恢复依赖项优化,以修复在使用 vite-plugin-cloudflare 并导入 Node.js 内置模块时出现的 depsOptimizer is required in dev mode 错误 (#13317)

不稳定变更

⚠️ 不稳定功能不建议在生产环境中使用

  • react-router - 引入 future.unstable_subResourceIntegrity 标志,该标志为浏览器将要加载的脚本生成带有 integrityimportmap (#13163)
  • react-router - 移除了对 route.unstable_lazyMiddleware 属性的支持 (#13294)
    • 为了懒加载中间件,您可以使用新的基于对象的 route.lazy.unstable_middleware API。
  • @react-router/dev - 当启用 future.unstable_viteEnvironmentApi 时,确保在配置了自定义 Vite base 的情况下,开发环境中的关键 CSS 也能正常工作 (#13305)

各软件包的变更

完整变更日志: v7.4.1...v7.5.0

v7.4.1

日期: 2025-03-28

安全公告

修复了一个安全漏洞,该漏洞由于端口清理不充分,允许通过 HostX-Forwarded-Host 头信息进行 URL 操作和潜在的缓存污染 (GHSA-4q56-crqp-v477/CVE-2025-31137)。

补丁变更

  • react-router - 对 route.lazy 函数的调用进行去重处理 (#13260)
  • @react-router/dev - 修复预渲染错误消息中的路径问题 (#13257)
  • @react-router/dev - 当 moduleDetection 设置为 force 时,修复虚拟模块的类型生成问题 (#13267)
  • @react-router/express - 改进对 x-forwarded-host 头信息的验证,以防止潜在的安全问题 (#13309)

不稳定变更

⚠️ 不稳定功能不建议在生产环境中使用

  • react-router - 修复 unstable_MiddlewareFunction 的类型,以避免当中间件不返回值时出现类型错误 (#13311)
  • react-router - 增加对 route.unstable_lazyMiddleware 函数的支持,以允许懒加载中间件逻辑 (#13210)
    • ⚠️ 我们目前不建议采用此 API,因为在中间件稳定发布之前我们很可能会更改它。
    • ⚠️ 如果您的应用当前从 route.lazy 返回 unstable_middleware,这可能是一个破坏性变更。
    • route.lazy 的返回值中不再支持 route.unstable_middleware 属性。
    • 如果您想懒加载中间件,必须使用 route.unstable_lazyMiddleware
  • @react-router/dev - 当同时启用 future.unstable_middlewarefuture.unstable_splitRouteModules 时,尽可能将 unstable_clientMiddleware 路由导出拆分到单独的块中 (#13210)
  • @react-router/dev - 通过确保仅在定义了 unstable_clientMiddleware 时,路由模块才在中间件阶段阻塞,从而提高 future.unstable_middleware 的性能 (#13210)

完整变更日志: v7.4.0...v7.4.1

v7.4.0

日期: 2025-03-19

次要变更

  • @react-router/dev - 为 virtual:react-router/server-build 模块生成类型 (#13152)

补丁变更

  • react-router - 修复 SPA 模式下初始加载重定向时的根 loader 数据问题 (#13222)
  • react-router - 在懒加载路由发现中为向上的非即时发现路由加载祖先的无路径/索引路由 (#13203)
  • react-router - 修复 ssr:true 应用中仅有 clientLoader 的路由的 shouldRevalidate 行为 (#13221)
  • @react-router/dev - 修复与其他使用 configureServer 和/或 configurePreviewServer 钩子的 Vite 插件的冲突 (#13184)

不稳定变更

⚠️ 不稳定功能不建议在生产环境中使用

  • react-router - 如果中间件抛出错误,确保我们只通过 next() 冒泡错误本身,不再泄露 MiddlewareError 实现细节 (#13180)
    • ⚠️ 如果您在中间件中 catchnext() 函数抛出的错误,这可能是一个破坏性变更。
  • react-router - 修复启用中间件时 RequestHandlerloadContext 参数类型 (#13204)
  • react-router - 将 Route.unstable_MiddlewareFunction 的返回值从 Response | void 更新为 Response | undefined (#13199)
  • @react-router/dev - 当 future.unstable_splitRouteModules 设置为 "enforce" 时,允许可拆分和不可拆分的根路由导出,因为它总是在一个单独的块中 (#13238)
  • @react-router/dev - 当启用 future.unstable_viteEnvironmentApi 时,允许覆盖默认 SSR 环境的插件(如 @cloudflare/vite-plugin)放在 React Router 插件之前或之后 (#13183)

各软件包的变更

完整变更日志: v7.3.0...v7.4.0

v7.3.0

日期: 2025-03-06

次要变更

  • fetcherKey 作为参数添加到 patchRoutesOnNavigation (#13061)

补丁变更

  • react-router - 在活动会话期间的新部署中检测并处理清单偏移问题 (#13061)
    • 在框架模式下,懒加载路由发现现在将在新部署后检测活动会话中的清单版本不匹配。
    • 在导航到未发现的路由时,这种不匹配将触发目标路径的文档重新加载。
    • 在对未发现路由的 fetcher 调用时,这种不匹配将触发当前路径的文档重新加载。
  • react-router - 在 SPA 模式下,跳过开发服务器中的资源路由流程 (#13113)
  • react-router - 修复使用 basename 时单次获取的 _root.data 请求 (#12898)
  • react-router - 修复包含 RecordloaderDataactionData 的类型 (#13139)
    • ⚠️ 对于已经采用 unstable_SerializesTo 的用户,这是一个破坏性变更——更多信息请参见下面“不稳定变更”部分的说明。
  • @react-router/dev - 修复对自定义客户端 build.rollupOptions.output.entryFileNames 的支持 (#13098)
  • @react-router/dev - 修复当配置了 serverBundles 选项或由预设(例如,来自 @vercel/react-routervercelPreset)提供时,prerender 选项的使用问题 (#13082)
  • @react-router/dev - 修复对自定义 build.assetsDir 的支持 (#13077)
  • @react-router/dev - 移除未使用的依赖项 (#13134)
  • @react-router/dev - 在“SPA 模式”服务器构建中,为除根路由外的所有路由创建存根,以避免当路由模块或其依赖项导入非 SSR 友好模块时出现问题 (#13023)
  • @react-router/dev - 移除未使用的 Vite 文件系统监视器 (#13133)
  • @react-router/dev - 修复当配置了 serverBundles 选项时,对自定义 SSR 构建输入的支持 (#13107)
    • ⚠️ 请注意,对于同时使用 future.unstable_viteEnvironmentApiserverBundles 选项的消费者,服务器包 ID 中不再支持连字符,因为它们也需要是有效的 Vite 环境名称。
  • @react-router/dev - 通过从开发服务器请求中剥离 HTTP/2 伪头信息,修复使用 HTTPS 时的开发服务器问题 (#12830)
  • @react-router/dev - 当使用 cloudflareDevProxy Vite 插件时,在第一次开发服务器请求时懒加载 Cloudflare 平台代理,以避免创建不必要的 workerd 进程 (#13016)
  • @react-router/dev - 修复布局路由及其相应索引路由在类型生成中的重复条目问题 (#13140)
  • @react-router/express - 更新 expresspeerDependency 以包含 v5 (https://github.com/remix-run/react-router/pull/13064) (#12961)

不稳定变更

⚠️ 不稳定功能不建议在生产环境中使用

  • react-router - 为客户端数据路由器添加 context 支持(不稳定)(#12941)
  • react-router - 支持路由上的中间件(不稳定)(#12941)
  • @react-router/dev - 修复当 SSR 环境被另一个插件配置为自定义 Vite.DevEnvironment 而不是默认的 Vite.RunnableDevEnvironment 时,使用 future.unstable_viteEnvironmentApi 出现的错误 (#13008)
  • @react-router/dev - 当启用 future.unstable_viteEnvironmentApi 并且 SSR 环境的 optimizeDeps.noDiscovery 被禁用时,定义 optimizeDeps.entriesoptimizeDeps.include (#13007)

客户端 context(不稳定)

您的应用程序 clientLoader/clientAction 函数(或库模式下的 loader/action)现在将在客户端接收一个 context 参数。这是一个 unstable_RouterContextProvider 的实例,您可以与类型安全的上下文(类似于 React.createContext)一起使用,它与相应的 unstable_clientMiddleware API 结合使用时最为有用。

import { unstable_createContext } from "react-router";

type User = {
  /*...*/
};

const userContext = unstable_createContext<User>();

const sessionMiddleware: Route.unstable_ClientMiddlewareFunction = async ({
  context,
}) => {
  let user = await getUser();
  context.set(userContext, user);
};

export const unstable_clientMiddleware = [sessionMiddleware];

export function clientLoader({ context }: Route.ClientLoaderArgs) {
  let user = context.get(userContext);
  let profile = await getProfile(user.id);
  return { profile };
}

与服务器端请求类似,每次导航(或 fetcher 调用)都会创建一个新的 context。如果您有希望为每个请求在上下文中填充的初始数据,您可以在应用程序的根部提供一个 unstable_getContext 函数。

  • 库模式 - createBrowserRouter(routes, { unstable_getContext })
  • 框架模式 - <HydratedRouter unstable_getContext>

此函数应返回一个类型为 unstable_InitialContext 的值,这是一个 Map<unstable_RouterContext, unknown>,包含上下文和初始值。

const loggerContext = unstable_createContext<(...args: unknown[]) => void>();

function logger(...args: unknown[]) {
  console.log(new Date.toISOString(), ...args);
}

function unstable_getContext() {
  let map = new Map();
  map.set(loggerContext, logger);
  return map;
}

中间件(不稳定)

中间件是在 future.unstable_middleware 标志后面实现的。要启用它,您必须在 react-router.config.ts 文件中启用该标志和类型。

import type { Config } from "@react-router/dev/config";
import type { Future } from "react-router";

declare module "react-router" {
  interface Future {
    unstable_middleware: true; // 👈 Enable middleware types
  }
}

export default {
  future: {
    unstable_middleware: true, // 👈 Enable middleware
  },
} satisfies Config;

⚠️ 中间件是不稳定的,不应在生产环境中采用。对于 clientMiddleware,在路由模块加载方面至少有一个已知的性能退化,我们将在稳定发布前解决这个问题。

⚠️ 启用中间件包含对传递给您的 loader/action 函数的 context 参数的破坏性变更——更多信息请参见下文。

启用后,路由可以定义一个中间件函数数组,这些函数将在路由处理程序运行之前顺序执行。这些函数接受与 loader/action 相同的参数,外加一个额外的 next 参数来运行剩余的数据管道。这允许中间件在处理程序执行前后执行逻辑。

// Framework mode
export const unstable_middleware = [serverLogger, serverAuth]; // server
export const unstable_clientMiddleware = [clientLogger]; // client

// Library mode
const routes = [
  {
    path: "/",
    // Middlewares are client-side for library mode SPA's
    unstable_middleware: [clientLogger, clientAuth],
    loader: rootLoader,
    Component: Root,
  },
];

这是一个简单的客户端日志记录中间件示例,可以放在根路由上:

const clientLogger: Route.unstable_ClientMiddlewareFunction = async (
  { request },
  next,
) => {
  let start = performance.now();

  // Run the remaining middlewares and all route loaders
  await next();

  let duration = performance.now() - start;
  console.log(`Navigated to ${request.url} (${duration}ms)`);
};

请注意,在上面的示例中,next/middleware 函数不返回任何内容。这是设计使然,因为在客户端没有像在服务器上运行的中间件那样需要通过网络发送的“响应”。数据都由有状态的 router 在幕后处理。

对于服务器端中间件,next 函数将返回 React Router 将通过网络发送的 HTTP Response,从而让您有机会根据需要进行更改。您可以抛出一个新的响应来短路并立即响应,或者您可以返回一个新的或修改过的响应来覆盖 next() 返回的默认响应。

const serverLogger: Route.unstable_MiddlewareFunction = async (
  { request, params, context },
  next,
) => {
  let start = performance.now();

  // 👇 Grab the response here
  let res = await next();

  let duration = performance.now() - start;
  console.log(`Navigated to ${request.url} (${duration}ms)`);

  // 👇 And return it here (optional if you don't modify the response)
  return res;
};

您可以从中间件中抛出一个 redirect 来短路任何剩余的处理。

import { sessionContext } from "../context";
const serverAuth: Route.unstable_MiddlewareFunction = (
  { request, params, context },
  next,
) => {
  let session = context.get(sessionContext);
  let user = session.get("user");
  if (!user) {
    session.set("returnTo", request.url);
    throw redirect("/login", 302);
  }
};

请注意,在这种情况下,您不需要进行任何后处理,因此不需要调用 next 函数或返回 Response

这是另一个使用服务器中间件检测 404 并检查 CMS 以获取重定向的示例:

const redirects: Route.unstable_MiddlewareFunction = async ({
  request,
  next,
}) => {
  // attempt to handle the request
  let res = await next();

  // if it's a 404, check the CMS for a redirect, do it last
  // because it's expensive
  if (res.status === 404) {
    let cmsRedirect = await checkCMSRedirects(request.url);
    if (cmsRedirect) {
      throw redirect(cmsRedirect, 302);
    }
  }

  return res;
};

有关 middleware API/设计的更多信息,请参阅决策文档

中间件 context 参数

当启用中间件时,您的应用程序将在 loader 和 action 中使用不同类型的 context 参数,以提供更好的类型安全性。context 将不再是 AppLoadContext,而是一个 ContextProvider 的实例,您可以与类型安全的上下文(类似于 React.createContext)一起使用。

import { unstable_createContext } from "react-router";
import { Route } from "./+types/root";
import type { Session } from "./sessions.server";
import { getSession } from "./sessions.server";

let sessionContext = unstable_createContext<Session>();

const sessionMiddleware: Route.unstable_MiddlewareFunction = ({
  context,
  request,
}) => {
  let session = await getSession(request);
  context.set(sessionContext, session);
  //                          ^ must be of type Session
};

// ... then in some downstream middleware
const loggerMiddleware: Route.unstable_MiddlewareFunction = ({
  context,
  request,
}) => {
  let session = context.get(sessionContext);
  //  ^ typeof Session
  console.log(session.get("userId"), request.method, request.url);
};

// ... or some downstream loader
export function loader({ context }: Route.LoaderArgs) {
  let session = context.get(sessionContext);
  let profile = await getProfile(session.get("userId"));
  return { profile };
}

如果您正在使用带有 getLoadContext 函数的自定义服务器,从服务器适配器层传递的初始上下文值的返回值不再是一个对象,而应返回一个 unstable_InitialContext (Map<RouterContext, unknown>)。

let adapterContext = unstable_createContext<MyAdapterContext>();

function getLoadContext(req, res): unstable_InitialContext {
  let map = new Map();
  map.set(adapterContext, getAdapterContext(req));
  return map;
}

unstable_SerializesTo

unstable_SerializesTo 添加了一种为其他库和框架作者(如 Apollo)在单次获取中注册自定义序列化类型的方法。它是通过一个品牌类型实现的,其品牌属性被设为可选,以便于转换任意值。

// without the brand being marked as optional
let x1 = 42 as unknown as unstable_SerializesTo<number>;
//          ^^^^^^^^^^

// with the brand being marked as optional
let x2 = 42 as unstable_SerializesTo<number>;

然而,这破坏了 loaderDataactionData 中任何 Record 类型的类型推断,因为这些类型现在会(错误地)匹配 unstable_SerializesTo。这影响了所有用户,而不仅仅是那些依赖 unstable_SerializesTo 的用户。为了修复这个问题,unstable_SerializesTo 的品牌属性被标记为必需而不是可选。

对于使用 unstable_SerializesTo 的库和框架作者,您可能需要在转换为 unstable_SerializesTo 之前添加 as unknown 类型转换。

各软件包的变更

完整变更日志: v7.2.0...v7.3.0

v7.2.0

日期: 2025-02-18

新功能

类型安全的 href 工具

在框架模式下,我们现在为您提供了一个完全类型安全的 href 工具,为您的应用程序中的链接提供路径自动完成和参数验证的温馨体验。

import { href } from "react-router";

export default function Component() {
  const link = href("/blog/:slug", { slug: "my-first-post" });
  //                ^ type-safe!     ^ Also type-safe!

  return (
    <main>
      <Link to={href("/products/:id", { id: "asdf" })} />
      <NavLink to={href("/:lang?/about", { lang: "en" })} />
    </main>
  );
}

如果您传递了错误的路径值或错误的参数值,现在会得到类型错误。

const badPath = href("/not/a/valid/path");
//                   ^ Error!

const badParam = href("/blog/:slug", { oops: "bad param" });
//                                     ^ Error!

带 SPA 回退的预渲染

此版本增强了在使用 ssr:false 进行预渲染时,将预渲染路径与以“SPA 模式”运行的其他路径结合使用的能力。

  • 如果您指定 ssr:false 但没有 prerender 配置,这被视为“SPA 模式”,生成的 index.html 文件将只渲染到根路由,并能够为任何有效的应用程序路径进行水合。
  • 如果您指定 ssr:false 并带有 prerender 配置,但*不*包括 / 路径(即 prerender: ['/blog/post']),那么我们仍然会生成一个“SPA 模式”的 index.html 文件,该文件可以为应用程序中的任何路径进行水合。
  • 如果您指定 ssr:false 并在 prerender 配置中包含 / 路径,则生成的 index.html 文件将特定于根索引路由,因此我们现在还将在 __spa-fallback.html 中生成一个单独的“SPA 模式”文件,您可以为非预渲染路径提供服务/水合。

更多信息,请参阅预渲染文档。

在 SPA 模式下允许根 loader

SPA 模式过去禁止在所有路由中使用 loader,以便我们可以为应用程序中的任何路径进行水合。然而,由于根路由总是在构建时渲染,我们可以为根路由解除这个限制。

为了在预渲染期间使用您的构建时 loader 数据,我们现在还将 loaderData 作为路由上 HydrateFallback 组件的可选属性公开。

  • 只要 HydrateFallback 是因为*子*路由正在加载而渲染,这个属性就会被定义。
  • 如果 HydrateFallback 是因为路由本身有自己的水合 clientLoader 而渲染,这个属性将是 undefined
    • 在 SPA 模式下,这将允许您将 loader 的根数据渲染到 SPA 模式的 HTML 文件中。

次要变更

  • react-router - 新的类型安全的 href 工具,保证链接指向您应用中的实际路径 (#13012)
  • @react-router/dev - 当使用 ssr:false 预渲染 / 路由时,生成一个“SPA 回退”HTML 文件 (#12948)
  • @react-router/dev - 在 SPA 模式下允许根路由中有 loader,因为它可以在构建时被调用/服务器渲染 (#12948)
    • Route.HydrateFallbackProps 现在也接收 loaderData

补丁变更

  • react-router - 禁用所有 ssr:false 应用的懒加载路由发现,而不仅仅是“SPA 模式”,因为没有运行时服务器来提供搜索参数配置的 __manifest 请求 (#12894)
    • 我们以前只为“SPA 模式”禁用此功能,但我们意识到它应该适用于所有 ssr:false 的应用。
    • 在那些 prerender 场景中,我们会预渲染 /__manifest 文件,但这做了一些关于静态文件服务器行为的不必要假设。
  • react-router - 在 SPA 模式下不应用单次获取重新验证的性能退化,因为没有服务器 HTTP 请求 (#12948)
  • react-router - 正确处理跨越预渲染/SPA 边界的重新验证 (#13021)
    • 在“混合”应用程序中,一些路由是预渲染的,另一些是从 SPA 回退提供的,我们需要避免在路径未被预渲染时发出 .data 请求,因为请求会返回 404。
    • 然而,我们在客户端不知道所有预渲染的路径。
      • ssr:false 模式下,所有 loader 数据都是静态的,因为它是在构建时生成的。
      • 路由必须使用 clientLoader 来做任何动态的事情。
      • 因此,如果一个路由只有 loader 而没有 clientLoader,我们默认禁用重新验证,因为没有新的数据可以检索。
      • 如果在我们的单次获取 dataStrategy 中没有 shouldLoad=true 的服务器 loader,我们会短路并跳过单次获取的 .data 请求逻辑。
      • 这确保了路由在提交后不会导致会 404 的 .data 请求。
  • react-router - 当设置 ssr:false 时,使开发服务器行为与静态文件服务器行为保持一致 (#12948)
    • 当不存在 prerender 配置时,仅 SSR 到根 HydrateFallback(SPA 模式)。
    • 当存在 prerender 配置但当前路径未被预渲染时,仅 SSR 到根 HydrateFallback(SPA 回退)。
    • 对于到非预渲染路径的 .data 请求,返回 404。
  • react-router - 提高框架模式下 CSS 副作用的预取性能 (#12889)
  • react-router - 在懒加载路由发现中正确处理中断的清单请求 (#12915)
  • @react-router/dev - 处理 Vite 配置中的自定义 envDir (#12969)
  • @react-router/dev - 修复 CLI 解析,以允许无参数的 npx react-router 用法 (#12925)
  • @react-router/dev - 当使用 prerender:true 时跳过仅有 action 的资源路由 (#13004)
  • @react-router/dev - 增强使用 ssr:false 时的无效导出检测 (#12948)
    • 在所有使用 ssr:false 的路由中禁止使用 headers/action 函数,因为没有运行时服务器来运行它们。
    • loader 函数则更细微,取决于给定的路由是否被预渲染。
      • 当使用 ssr:false 且没有 prerender 配置时,只有 root 路由可以有 loader
      • 当使用 ssr:false 并有 prerender 配置时,只有与 prerender 路径匹配的路由可以有 loader
  • @react-router/dev - 在 ssr:false + prerender 应用中,对以下边缘情况在构建时报错:(#13021)
    • 父路由只有一个 loader(没有 clientLoader)。
    • 父路由被预渲染。
    • 父路由有未被预渲染的子路由。
    • 这意味着当通过 SPA 回退加载子路径时,父路由将没有任何 loaderData,因为没有服务器来运行 loader
    • 这可以通过添加父 clientLoader 或预渲染子路径来解决。
    • 如果您添加一个 clientLoader,在非预渲染路径上调用 serverLoader() 将会抛出 404。
  • @react-router/dev - 将预渲染的资源路由 .data 文件限制为仅目标路由 (#13004)
  • @react-router/dev - 修复二进制文件的预渲染问题 (#13039)
  • @react-router/dev - 修复重复参数的类型生成 (#13012)
    • 在 React Router 中,路径参数按其名称键入,因此对于像 /a/:id/b/:id?/c/:id 这样的路径模式,最后一个 :id 将设置 useParamsparams 属性中 id 的值。
      • 例如,/a/1/b/2/c/3 在运行时将导致值为 { id: 3 }
    • 以前,为参数生成的类型错误地将重复参数建模为数组。
      • 例如,/a/1/b/2/c/3 生成的类型类似 { id: [1,2,3] }
    • 为了与运行时行为保持一致,生成的类型现在正确地模拟了路径参数的“最后一个获胜”语义。
      • 例如,/a/1/b/2/c/3 现在生成的类型类似 { id: 3 }
  • @react-router/dev - 修复加载 package.json 以执行 react-router --version 的路径问题 (#13012)

不稳定变更

⚠️ 不稳定功能不建议在生产环境中使用

  • react-router - 为库作者添加 unstable_SerializesTo 品牌类型,以注册可被 React Router 流式格式(turbo-stream)序列化的类型 (#12264)
  • @react-router/dev - 通过 future.unstable_splitRouteModules 为框架模式添加对拆分路由模块的不稳定支持 (#11871)
  • @react-router/dev - 添加 future.unstable_viteEnvironmentApi 标志以启用实验性的 Vite 环境 API 支持 (#12936)

拆分路由模块(不稳定)

⚠️ 此功能目前是不稳定的,通过 future.unstable_splitRouteModules 标志启用。我们欢迎任何感兴趣的用户在本地试用并提供反馈,但我们不建议在生产环境中使用它。

如果您确实选择在生产环境中采用此标志,请确保对您的生产构建进行充分测试,以确保优化按预期工作。

路由模块 API 的便利之一是路由所需的一切都在一个文件中。不幸的是,在使用 clientLoaderclientActionHydrateFallback API 时,这在某些情况下会带来性能成本。

作为一个基本示例,请考虑这个路由模块:

import { MassiveComponent } from "~/components";

export async function clientLoader() {
  return await fetch("https://example.com/api").then((response) =>
    response.json(),
  );
}

export default function Component({ loaderData }) {
  return <MassiveComponent data={loaderData} />;
}

在此示例中,我们有一个最小的 clientLoader 导出,它进行一个基本的 fetch 调用,而默认的组件导出则要大得多。这对性能是一个问题,因为这意味着如果我们想在客户端导航到此路由,必须在客户端加载器开始运行之前下载整个路由模块。

将其可视化为时间线:

在以下时间线图中,路由模块条内使用不同的字符表示正在导出的不同路由模块 API。

Get Route Module:  |--=======|
Run clientLoader:            |-----|
Render:                            |-|

相反,我们希望将其优化为以下内容:

Get clientLoader:  |--|
Get Component:     |=======|
Run clientLoader:     |-----|
Render:                     |-|

为了实现此优化,React Router 将在生产构建过程中将路由模块拆分为多个较小的模块。在这种情况下,我们最终将得到两个独立的虚拟模块——一个用于客户端加载器,一个用于组件及其依赖项。

export async function clientLoader() {
  return await fetch("https://example.com/api").then((response) =>
    response.json(),
  );
}
import { MassiveComponent } from "~/components";

export default function Component({ loaderData }) {
  return <MassiveComponent data={loaderData} />;
}

💡 此优化在框架模式下自动应用,但您也可以通过 route.lazy 在库模式下实现它,并将您的路由编写在多个文件中,如我们关于懒加载路由模块的博客文章中所述。

现在这些可作为单独的模块使用,客户端加载器和组件可以并行下载。这意味着客户端加载器可以在准备好后立即执行,而不必等待组件。

当使用更多路由模块 API 时,此优化效果更为显著。例如,当使用 clientLoaderclientActionHydrateFallback 时,单个路由模块在客户端导航期间的时间线可能如下所示:

Get Route Module:     |--~~++++=======|
Run clientLoader:                     |-----|
Render:                                     |-|

这将被优化为以下内容:

Get clientLoader:     |--|
Get clientAction:     |~~|
Get HydrateFallback:  SKIPPED
Get Component:        |=======|
Run clientLoader:        |-----|
Render:                        |-|

请注意,此优化仅在被拆分的路由模块 API 不在同一文件中共享代码时才有效。例如,以下路由模块无法被拆分:

import { MassiveComponent } from "~/components";

const shared = () => console.log("hello");

export async function clientLoader() {
  shared();
  return await fetch("https://example.com/api").then((response) =>
    response.json(),
  );
}

export default function Component({ loaderData }) {
  shared();
  return <MassiveComponent data={loaderData} />;
}

此路由仍然可以工作,但由于客户端加载器和组件都依赖于在同一文件中定义的 shared 函数,它将被降级为一个单一的路由模块。

为避免这种情况,您可以将导出之间共享的任何代码提取到一个单独的文件中。例如:

export const shared = () => console.log("hello");

然后您可以在路由模块中导入此共享代码,而不会触发降级:

import { MassiveComponent } from "~/components";
import { shared } from "./shared";

export async function clientLoader() {
  shared();
  return await fetch("https://example.com/api").then((response) =>
    response.json(),
  );
}

export default function Component({ loaderData }) {
  shared();
  return <MassiveComponent data={loaderData} />;
}

由于共享代码在其自己的模块中,React Router 现在能够将此路由模块拆分为两个独立的虚拟模块:

import { shared } from "./shared";

export async function clientLoader() {
  shared();
  return await fetch("https://example.com/api").then((response) =>
    response.json(),
  );
}
import { MassiveComponent } from "~/components";
import { shared } from "./shared";

export default function Component({ loaderData }) {
  shared();
  return <MassiveComponent data={loaderData} />;
}

如果您的项目对性能特别敏感,您可以将 unstable_splitRouteModules 未来标志设置为 "enforce"

export default {
  future: {
    unstable_splitRouteModules: "enforce",
  },
};

此设置将在任何路由模块无法被拆分时引发错误。

Error splitting route module: routes/example/route.tsx

- clientLoader

This export could not be split into its own chunk because it shares code with other exports. You should extract any shared code into its own module and then import it within the route module.

各软件包的变更

完整变更日志: v7.1.5...v7.2.0

v7.1.5

日期: 2025-01-31

补丁变更

  • react-router - 修复在 7.1.4 版本中通过 #12800 引入的回归问题,该问题导致使用懒加载路由发现(patchRoutesOnNavigation)的应用程序在 splat 路由内导航到哈希路由时出现问题 (#12927)

完整变更日志: v7.1.4...v7.1.5

v7.1.4

日期: 2025-01-30

补丁变更

  • @react-router/dev - 在使用 unstable_optimizeDeps 未来标志时,正确解析 Windows 文件路径以扫描 Vite 的依赖优化 (#12637)
  • @react-router/dev - 修复使用自定义服务器时的预渲染问题 - 以前我们最终尝试导入用户自定义服务器,而实际上我们想导入虚拟服务器构建模块 (#12759)
  • react-router - 在单次获取响应中正确处理不能有主体的状态码(204 等)(#12760)
  • react-router - 当抛出 data() 结果时,正确地将头信息作为 errorHeaders 冒泡 (#12846)
    • 如果也从 headers 返回,则避免 Set-Cookie 头信息的重复
  • react-router - 停止对返回原始字符串/对象的资源路由报错,而是将它们序列化为 text/plainapplication/json 响应 (#12848)
    • 这仅适用于作为没有 .data 扩展名的资源路由访问时
    • 当从单次获取 .data 请求访问时,它们仍将通过 turbo-stream 进行编码
  • react-router - 优化懒加载路由发现的路径发现,优先使用在 body 级别的单个 querySelectorAll 调用,而不是在子树级别的多次调用 (#12731)
  • react-router - 通过在可能的情况下跳过冗余的 matchRoutes 调用来优化路由匹配 (#12800, #12882)
  • react-router - 内部重组以清理一些重复的路由模块类型 (#12799)

完整变更日志: v7.1.3...v7.1.4

v7.1.3

日期: 2025-01-17

补丁变更

  • @react-router/dev - 修复 revealroutes CLI 命令 (#12745)

完整变更日志: v7.1.2...v7.1.3

v7.1.2

日期: 2025-01-16

补丁变更

  • react-router - 修复在 fetcher 卸载时数据层中 fetcher 数据清理的问题 (#12681)
  • react-router - 不再依赖 symbol 来过滤 loader 数据中的 redirect 响应 (#12694)
    • 以前,一些项目会收到类似这样的类型检查错误:
      error TS4058: Return type of exported function has or is using name 'redirectSymbol' from external module "node_modules/..." but cannot be named.
      
    • 现在 redirect 响应类型不再使用 symbol,这些错误应该不再出现。
  • @react-router/dev - 修复 Vite v6 中的默认外部条件 (#12644)
    • 此修复解决了某些 npm 包的解析问题。
  • @react-router/dev - 修复路径缺少前导斜杠时预渲染 html/data 文件的匹配问题 (#12684)
  • @react-router/dev - 在运行时启用时,使用 module-sync 服务器条件。这修复了在使用对 React Router 有对等依赖的库时,在 Node 22.10.0+ 开发过程中的 React 上下文不匹配问题(例如 useHref() may be used only in the context of a <Router> component.)(#12729)
  • @react-router/dev - 修复 react-refresh 的 source map (#12686)

完整变更日志: v7.1.1...v7.1.2

v7.1.1

日期: 2024-12-23

补丁变更

  • @react-router/dev - 修复当可选参数传递给 CLI 时发生的崩溃问题 (#12609)

完整变更日志: v7.1.0...v7.1.1

v7.1.0

日期: 2024-12-20

次要变更

  • 增加对 Vite v6 的支持 (#12469)

补丁变更

  • react-router - 抛出未包装的单次获取 redirect,以与单次获取之前的行为保持一致 (#12506)
  • react-router - 在推断 loader 数据类型时忽略重定向 (#12527)
  • react-router - 移除 <Link prefetch> 警告,该警告在懒加载路由发现的世界中容易出现误报 (#12485)
  • create-react-router - 修复缺失的 fs-extra 依赖 (#12556)
  • @react-router/dev/@react-router/serve - 如果 NODE_ENV 尚未设置,则正确初始化,以兼容 React 19 (#12578)
  • @react-router/dev - 从 ServerRouter 中移除剩余/未使用的 abortDelay 属性,并更新默认的 entry.server.tsx 以使用新的 streamTimeout 值用于单次获取 (#12478)
    • abortDelay 功能已在 v7 中移除,因为它与 Remix v2 的 defer 实现耦合,但此属性的移除被遗漏了。
    • 如果您仍在 entry.server 文件中使用此属性,您的应用可能没有按预期中止流,您将需要采用随单次获取引入的新的 streamTimeout 值。
  • @react-router/fs-routes - 如果路由目录缺失,则在 flatRoutes 中抛出错误 (#12407)

各软件包的变更

完整变更日志: v7.0.2...v7.1.0

v7.0.2

日期: 2024-12-02

补丁变更

  • react-router - 临时在 export map 中只使用一个构建,以便包可以对 react router 有一个对等依赖 (#12437)
  • @react-router/dev - 支持 moduleResolution Node16NodeNext (#12440)
  • @react-router/dev - 为子路由生成更宽泛的 matchesparams 类型 (#12397)
    • 在运行时,matches 包括子路由匹配,params 包括子路由路径参数。
    • 但以前,我们只为父路由和当前路由在 matchesparams 中生成类型。
    • 为了使我们生成的类型更接近运行时行为,我们现在在访问子路由信息时生成更宽容、更宽泛的类型。

完整变更日志: v7.0.1...v7.0.2

v7.0.1

日期: 2024-11-22

补丁变更

  • @react-router/dev - 确保在 Vite 开发服务器重启时清理类型生成文件监视器 (#12331)
  • @react-router/dev - 将路由 error 作为属性传递给 ErrorBoundary (#12338)

完整变更日志: v7.0.0...v7.0.1

v7.0.0

日期: 2024-11-21

破坏性变更

包重组

  • react-router-dom@remix-run/react@remix-run/server-runtime@remix-run/router 已合并到 react-router 包中。
    • 为简化迁移,v7 中仍发布 react-router-dom,作为 react-router 所有内容的重新导出。
  • @remix-run/cloudflare-pages@remix-run/cloudflare-workers 已合并到 @react-router/cloudflare 包中。
  • react-router-dom-v5-compatreact-router-native 包从 v7 开始被移除。

移除的适配器重新导出

Remix v2 过去常常通过各种运行时包(nodecloudflaredeno)重新导出所有常见的 @remix-run/server-runtime API,这样您就不需要在 package.json 中添加额外的 @remix-run/server-runtime 依赖。随着包合并到 react-router 中,这些常见的 API 现在不再通过运行时适配器重新导出。您应该从 react-router 导入所有常见的 API,并仅从运行时包导入特定于运行时的 API。

// Runtime-specific APIs
import { createFileSessionStorage } from "@react-router/node";
// Runtime-agnostic APIs
import { redirect, useLoaderData } from "react-router";

移除的 API

以下 API 已在 React Router v7 中移除:

  • json
  • defer
  • unstable_composeUploadHandlers
  • unstable_createMemoryUploadHandler
  • unstable_parseMultipartFormData

最低版本要求

React Router v7 需要以下最低版本

  • node@20
    • React Router 不再提供 installGlobals 方法来填充 fetch API。
  • react@18, react-dom@18

已采纳的未来标志行为

Remix 和 React Router 遵循API 开发策略,利用“未来标志”来避免在主要版本中引入大量破坏性变更。相反,破坏性变更在次要版本中通过标志引入,允许用户自行选择加入。在下一个主要版本中,所有未来标志的行为都成为默认行为。

以下先前标记的行为现在是 React Router v7 中的默认行为:

  • React Router v6 标志
    • future.v7_relativeSplatPath
    • future.v7_startTransition
    • future.v7_fetcherPersist
    • future.v7_normalizeFormMethod
    • future.v7_partialHydration
    • future.v7_skipActionStatusRevalidation
  • Remix v2 标志
    • future.v3_fetcherPersist
    • future.v3_relativeSplatPath
    • future.v3_throwAbortReason
    • future.v3_singleFetch
    • future.v3_lazyRouteDiscovery
    • future.v3_optimizeDeps

Vite 编译器

Remix Vite 插件是使用 React Router v7 构建全栈 SSR 应用的正确方式。以前基于 esbuild 的编译器已不再可用。

重命名 vitePlugincloudflareDevProxyVitePlugin

对于从 Remix 迁移到 React Router 的消费者,vitePlugincloudflareDevProxyVitePlugin 导出已被重命名并移动 (#11904)

-import {
-  vitePlugin as remix,
-  cloudflareDevProxyVitePlugin,
-} from "@remix/dev";

+import { reactRouter } from "@react-router/dev/vite";
+import { cloudflareDevProxy } from "@react-router/dev/vite/cloudflare";

移除 manifest 选项

对于从 Remix 迁移到 React Router 的消费者,Vite 插件的 manifest 选项已被移除。manifest 选项已被更强大的 buildEnd 钩子取代,因为它接收 buildManifest 参数。如果需要,您仍然可以将构建清单写入磁盘,但您可能会发现将任何依赖于构建清单的逻辑写在 buildEnd 钩子本身内更方便。(#11573)

如果您曾使用 manifest 选项,可以将其替换为将清单写入磁盘的 buildEnd 钩子,如下所示:

// react-router.config.ts
import { type Config } from "@react-router/dev/config";
import { writeFile } from "node:fs/promises";

export default {
  async buildEnd({ buildManifest }) {
    await writeFile(
      "build/manifest.json",
      JSON.stringify(buildManifest, null, 2),
      "utf-8"
    );
  },
} satisfies Config;

暴露的 Router Promises

由于 React 19 将对在渲染过程中处理 Promise 提供一流的支持(通过 React.useuseAction),我们现在可以放心地暴露先前返回 undefined 的 API 的 Promise。

  • useNavigate()
  • useSubmit()
  • useFetcher().load
  • useFetcher().submit
  • useRevalidator().revalidate()

其他值得注意的变更

routes.ts

当使用 React Router Vite 插件时,路由在 app/routes.ts 中定义。路由配置通过 routes 导出,符合 RouteConfig 类型。提供了路由辅助函数 routeindexlayout,以使声明式类型安全的路由定义更容易。

// app/routes.ts
import {
  type RouteConfig,
  route,
  index,
  layout,
} from "@react-router/dev/routes";

export const routes: RouteConfig = [
  index("./home.tsx"),
  route("about", "./about.tsx"),

  layout("./auth/layout.tsx", [
    route("login", "./auth/login.tsx"),
    route("register", "./auth/register.tsx"),
  ]),

  route("concerts", [
    index("./concerts/home.tsx"),
    route(":city", "./concerts/city.tsx"),
    route("trending", "./concerts/trending.tsx"),
  ]),
];

对于从 Remix 迁移到 React Router 的消费者,您仍然可以使用 @react-router/fs-routes 包在 routes.ts 中配置基于文件系统的路由。一个重现默认 Remix 设置的最小路由配置如下所示:

// app/routes.ts
import { type RouteConfig } from "@react-router/dev/routes";
import { flatRoutes } from "@react-router/fs-routes";

export const routes: RouteConfig = flatRoutes();

如果您想从基于文件系统的路由迁移到基于配置的路由,您可以通过将异步 flatRoutes 函数的结果扩展到基于配置的路由数组中来混合使用这两种方法。

// app/routes.ts
import { type RouteConfig, route } from "@react-router/dev/routes";
import { flatRoutes } from "@react-router/fs-routes";

export const routes: RouteConfig = [
  // Example config-based route:
  route("/hello", "./routes/hello.tsx"),

  // File system routes scoped to a different directory:
  ...(await flatRoutes({
    rootDirectory: "fs-routes",
  })),
];

如果您曾使用 Remix 的 routes 选项来使用替代的文件系统路由约定,您可以使用 @react-router/remix-config-routes-adapter 将它们适配到新的 RouteConfig 格式。

例如,如果您在 Remix v2 中使用Remix v1 路由约定,您可以将 @react-router/remix-config-routes-adapter@remix-run/v1-route-convention 结合使用,以将其适配到 React Router。

// app/routes.ts
import { type RouteConfig } from "@react-router/dev/routes";
import { remixConfigRoutes } from "@react-router/remix-config-routes-adapter";
import { createRoutesFromFolders } from "@remix-run/v1-route-convention";

export const routes: RouteConfig = remixConfigRoutes(async (defineRoutes) => {
  return createRoutesFromFolders(defineRoutes, {
    ignoredFilePatterns: ["**/.*", "**/*.css"],
  });
});

另请注意,如果您曾使用 Remix 的 routes 选项来定义基于配置的路由,您也可以使用 @react-router/remix-config-routes-adapter 以最少的代码更改将它们适配到新的 RouteConfig 格式。虽然这提供了一条快速的迁移路径,但我们建议将任何基于配置的路由从 Remix 迁移到新的 RouteConfig 格式,因为这是一个相当直接的迁移。

// app/routes.ts
-import { type RouteConfig } from "@react-router/dev/routes";
+import { type RouteConfig, route } from "@react-router/dev/routes";
-import { remixConfigRoutes } from "@react-router/remix-config-routes-adapter";

-export const routes: RouteConfig = remixConfigRoutes(async (defineRoutes) => {
-  defineRoutes((route) => {
-    route("/parent", "./routes/parent.tsx", () => [
-      route("/child", "./routes/child.tsx"),
-    ]);
-  });
-});
+export const routes: RouteConfig = [
+  route("/parent", "./routes/parent.tsx", [
+    route("/child", "./routes/child.tsx"),
+  ]),
+];

类型安全改进

React Router 现在为您的每个路由模块生成类型,并将类型化的 props 传递给路由模块组件的导出 (#11961, #12019)。您可以通过从 ./+types/<route filename without extension> 导入它们来访问这些类型。

更多详情请参阅操作指南 > 路由模块类型安全解释 > 类型安全

预渲染

React Router v7 在 Vite 插件中包含了一个新的 prerender 配置,以支持 SSG 用例。这将在构建时预渲染您的 .html.data 文件,以便您可以在运行时从正在运行的服务器或 CDN 静态提供它们 (#11539)。

export default defineConfig({
  plugins: [
    reactRouter({
      async prerender({ getStaticPaths }) {
        let slugs = await fakeGetSlugsFromCms();
        return [
          ...getStaticPaths(),
          ...slugs.map((slug) => `/product/${slug}`),
        ];
      },
    }),
    tsconfigPaths(),
  ],
});

async function fakeGetSlugsFromCms() {
  await new Promise((r) => setTimeout(r, 1000));
  return ["shirt", "hat"];
}

主要变更 (react-router)

  • 移除原始的 defer 实现,转而通过单次获取和 turbo-stream 使用原生 Promise (#11744)
    • 这从 React Router 中移除了以下导出:
      • defer
      • AbortedDeferredError
      • type TypedDeferredData
      • UNSAFE_DeferredData
      • UNSAFE_DEFERRED_SYMBOL
  • 将包合并到 react-router 中 (#11505)
    • @remix-run/router
    • react-router-dom
    • @remix-run/server-runtime
    • @remix-run/testing
    • 请注意,react-router-dom 包得以保留以简化迁移,但它只是重新导出 react-router 的所有 API。
  • 放弃对 Node 16 的支持,React Router SSR 现在需要 Node 18 或更高版本 (#11391, #11690)
  • 移除 future.v7_startTransition 标志 (#11696)
  • 从以下 API 中暴露底层的 router promise,以便在 React 19 API 中组合使用:(#11521)
  • 移除 future.v7_normalizeFormMethod 未来标志 (#11697)
  • 导入/导出清理 (#11840)
    • 移除了以下以前是 @remix-run/router 公共 API 的导出:
      • 类型
        • AgnosticDataIndexRouteObject
        • AgnosticDataNonIndexRouteObject
        • AgnosticDataRouteMatch
        • AgnosticDataRouteObject
        • AgnosticIndexRouteObject
        • AgnosticNonIndexRouteObject
        • AgnosticRouteMatch
        • AgnosticRouteObject
        • TrackedPromise
        • unstable_AgnosticPatchRoutesOnMissFunction
        • Action -> 通过 react-router 导出为 NavigationType
        • Router 导出为 RemixRouter,以区别于 RR 的 <Router>
      • API
        • getToPathname (@private)
        • joinPaths (@private)
        • normalizePathname (@private)
        • resolveTo (@private)
        • stripBasename (@private)
        • createBrowserHistory -> 推荐使用 createBrowserRouter
        • createHashHistory -> 推荐使用 createHashRouter
        • createMemoryHistory -> 推荐使用 createMemoryRouter
        • createRouter
        • createStaticHandler -> 推荐使用 RR Dom 中的包装器 createStaticHandler
        • getStaticContextFromError
    • 移除了以下以前是 react-router 公共 API 的导出:
      • Hash
      • Pathname
      • Search
  • 从内部化的 @remix-run/router 包中移除 future.v7_prependBasename (#11726)
  • 从内部化的 @remix-run/router 包中移除 future.v7_throwAbortReason (#11728)
  • 为所有包添加 exports 字段 (#11675)
  • RemixContext 重命名为 FrameworkContext (#11705)
  • 将最低 React 版本更新为 18 (#11689)
  • PrefetchPageDescriptorPageLinkDescriptor 替换 (#11960)
  • 移除 future.v7_partialHydration 标志 (#11725)
    • 这也移除了 <RouterProvider fallbackElement> 属性。
      • 要迁移,请将 fallbackElement 移动到根路由的 hydrateFallbackElement/HydrateFallback 上。
    • 还值得注意的是,这个未来标志有一个相关的破坏性变更。
      • 没有 future.v7_partialHydration(当使用 fallbackElement 时),state.navigation 在初始加载期间被填充。
      • 使用 future.v7_partialHydration 时,state.navigation 在初始加载期间保持 "idle" 状态。
  • 移除 future.v7_relativeSplatPath 未来标志 (#11695)
  • 移除剩余的未来标志 (#11820)
    • React Router v7_skipActionErrorRevalidation
    • Remix v3_fetcherPersist, v3_relativeSplatPath, v3_throwAbortReason
  • createRemixStub 重命名为 createRoutesStub (#11692)
  • 移除 @remix-run/router 已弃用的 detectErrorBoundary 选项,推荐使用 mapRouteProperties (#11751)
  • 添加 react-router/dom 子路径导出,以正确地将 react-dom 作为可选的 peerDependency (#11851)
    • 这确保我们不会为了访问 ReactDOM.flushSync() 而在 <RouterProvider> 中盲目地 import ReactDOM from "react-dom",因为这会破坏在非 DOM 环境中使用 createMemoryRouter 的情况。
    • DOM 环境应该从 react-router/dom 导入,以获取使 ReactDOM.flushSync() 可用的正确组件。
      • 如果您正在使用 Vite 插件,请在您的 entry.client.tsx 中使用它:
        • import { HydratedRouter } from 'react-router/dom'
      • 如果您未使用 Vite 插件,而是手动调用 createBrowserRouter/createHashRouter
        • import { RouterProvider } from "react-router/dom"
  • 移除 future.v7_fetcherPersist 标志 (#11731)
  • 允许从 loader 和 action 返回 undefined (#11680, #12057)
  • entry.client 中使用 createRemixRouter/RouterProvider,而不是 RemixBrowser (#11469)
  • 移除已弃用的 json 工具 (#12146)
    • 如果您仍需要在应用中构造 JSON 响应,可以使用 Response.json

主要变更 (@react-router/*)

  • 移除 future.v3_singleFetch 标志 (#11522)
  • 放弃对 Node 16 和 18 的支持,将最低 Node 版本更新为 20 (#11690, #12171)
    • 移除 installGlobals(),因为这应该不再需要。
  • 为所有包添加 exports 字段 (#11675)
  • 不再通过不同的运行时/适配器包重新导出 react-router 的 API (#11702)
  • 对于从 Remix 迁移到 React Router 的消费者,使用 cookie 和 session API 时现在需要 Web Crypto APIcrypto 全局变量。
    • 这意味着以下 API 是从 react-router 而不是特定平台的包中提供的:(#11837)
      • createCookie
      • createCookieSessionStorage
      • createMemorySessionStorage
      • createSessionStorage
    • 对于运行旧版本 Node 的消费者,@remix-run/node 中的 installGlobals 函数已更新为定义 globalThis.crypto,使用 Node 的 require('node:crypto').webcrypto 实现
    • 由于特定平台的包不再需要实现此 API,以下低级 API 已被移除:
      • createCookieFactory
      • createSessionStorageFactory
      • createCookieSessionStorageFactory
      • createMemorySessionStorageFactory
  • 整合以前在 @remix-run/router@remix-run/server-runtime@remix-run/react 中重复的类型,因为它们现在都存在于 react-router 中 (#12177)
    • 例如:LoaderFunction, LoaderFunctionArgs, ActionFunction, ActionFunctionArgs, DataFunctionArgs, RouteManifest, LinksFunction, Route, EntryRoute
    • “remix”代码使用的 RouteManifest 类型现在稍微更严格,因为它使用的是以前的 @remix-run/routerRouteManifest
      • Record<string, Route> -> Record<string, Route | undefined>
    • 移除了 AppData 类型,转而在其使用的少数位置内联 unknown
    • 移除了 ServerRuntimeMeta* 类型,替换为它们所复制的 Meta* 类型
  • 将 Remix v2 类型泛型迁移到 React Router (#12180)
    • 提供这些泛型是为了 Remix v2 的迁移
    • 这些泛型及其所在的 API 应被视为非正式弃用,推荐使用新的 Route.* 类型
    • 从 React Router v6 迁移的用户可能不应使用这些新泛型,而应直接迁移到 Route.* 类型
    • 对于 React Router v6 用户,这些泛型是新增的,除了一个例外,不应影响您的应用
      • useFetcher 之前有一个可选的泛型(主要由 Remix v2 使用),它期望的是数据类型
      • 在 v7 中,这已更新为期望生成数据的函数类型(即 typeof loader/typeof action
      • 因此,您应该更新您的用法
        • useFetcher<LoaderData>()
        • useFetcher<typeof loader>()
  • cookie 依赖更新至 ^1.0.1 - 请参阅 发布说明 了解任何破坏性变更 (#12172)
  • @react-router/cloudflare - 对于迁移到 React Router 的 Remix 用户,现在 @react-router/cloudflare 包中为 React Router 用户提供了所有来自 @remix-run/cloudflare-pages 的导出。不再有单独的 Cloudflare Pages 包。 (#11801)
  • @react-router/cloudflare - @remix-run/cloudflare-workers 包已被弃用。迁移到 React Router 的 Remix 用户应直接使用 @react-router/cloudflare 包。关于如何在 Cloudflare Workers 环境中使用 @react-router/cloudflare 的指导,请参考 Cloudflare Workers 模板。 (#11801)
  • @react-router/dev - 对于迁移到 React Router 的 Remix 用户,vitePlugincloudflareDevProxyVitePlugin 导出项已被重命名和移动。 (#11904)
  • @react-router/dev - 对于使用 Vite 插件的 buildEnd 钩子并迁移到 React Router 的 Remix 用户,解析出的 reactRouterConfig 对象不再包含 publicPath 属性,因为这属于 Vite,而不是 React Router (#11575)
  • @react-router/dev - 对于迁移到 React Router 的 Remix 用户,Vite 插件的 manifest 选项已被移除 (#11573)
  • @react-router/dev - 将默认的 isbot 版本更新到 v5,并放弃对 isbot@3 的支持 (#11770)
    • 如果您的 package.json 中有 isbot@4isbot@5
      • 您无需做任何更改
    • 如果您的 package.json 中有 isbot@3 并且您的仓库中有自己的 entry.server.tsx 文件
      • 您无需做任何更改
      • 您可以独立于 React Router v7 升级,将 isbot 升级到 @5
    • 如果您的 package.json 中有 isbot@3 并且您的仓库中没有自己的 entry.server.tsx 文件
      • 您正在使用 React Router v7 提供的内部默认入口,您需要在 package.json 中将 isbot 升级到 @5
  • @react-router/dev - 对于迁移到 React Router 的 Remix 用户,Vite 清单(即 .vite/manifest.json)现在被写入每个构建子目录中,例如 build/client/.vite/manifest.jsonbuild/server/.vite/manifest.json,而不是 build/.vite/client-manifest.jsonbuild/.vite/server-manifest.json。这意味着构建输出现在更接近于一个典型的 Vite 项目。 (#11573)
    • 最初,Remix Vite 插件将所有 Vite 清单移动到根级的 build/.vite 目录,以避免在生产环境中意外提供它们,特别是来自客户端构建的。后来通过添加额外的逻辑对此进行了改进,该逻辑在构建过程结束时删除这些 Vite 清单文件,除非在应用程序的 Vite 配置中启用了 Vite 的 build.manifest。这大大降低了在生产环境中意外提供 Vite 清单的风险,因为它们仅在明确要求时才存在。因此,我们现在可以假设用户知道他们需要自己管理这些额外的文件,并且 React Router 可以安全地生成更标准的 Vite 构建输出。

次要变更

  • react-router - 将参数、加载器数据和操作数据作为路由组件导出的 props (#11961)
  • react-router - 添加路由模块类型生成 (#12019)
  • react-router - 移除重复的 RouterProvider 实现 (#11679)
  • react-router - 稳定 unstable_dataStrategy (#11969)
  • react-router - 稳定 unstable_patchRoutesOnNavigation (#11970)
  • react-router - 在使用 Remix SSR 时为 Link/NavLink 添加预取支持 (#11402)
  • react-router - 增强 ScrollRestoration,使其能在 SSR 渲染的文档加载时正确恢复滚动位置 (#11401)
  • @react-router/dev - 在 React Router vite 插件中添加对 prerender 配置的支持,以支持现有的 SSG 用例 (#11539)
  • @react-router/dev - 移除内部的 entry.server.spa.tsx 实现,该实现与 Single Fetch 异步水合方法不兼容 (#11681)
  • @react-router/serve:更新 express.static 配置以支持新的 prerender API (#11547)
    • build/client/assets 文件夹中的资源像以前一样提供,带有 1 年不可变的 Cache-Control 标头
    • assets 之外的静态文件,如预渲染的 .html.data 文件,不带特定的 Cache-Control 标头提供
    • .data 文件以 Content-Type: text/x-turbo 提供
      • 出于某种原因,当通过 express.static 添加此项时,似乎还会为 .data 文件添加一个 Cache-Control: public, max-age=0

补丁变更

  • substr 替换为 substring (#12080)
  • react-router - 修复从 loaders/actions 使用 data() 返回的重定向 (#12021)
  • @react-router/dev - 为资源路由启用预渲染 (#12200)
  • @react-router/dev - 相对于扁平输出文件结构解析配置目录 (#12187)

按包分类的变更

完整更新日志: v6.28.0...v7.0.0

React Router v6 发布版本

v6.30.1

日期:2025-05-20

补丁变更

  • 部分回滚在 6.29.0 中添加的旨在减少 matchRoutes 调用的优化,因为它引发了其他问题 (#13623)
  • v7_relativeSplatPath 设置为 false 时,停止记录无效警告 (#13502)

完整更新日志: v6.30.0...v6.30.1

v6.30.0

日期:2025-02-27

次要变更

  • fetcherKey 作为参数添加到 patchRoutesOnNavigation (#13109)

补丁变更

  • 修复在 6.29.0 中由 #12169 引入的回归问题,该问题导致在使用惰性路由发现(patchRoutesOnNavigation)的应用中,导航到 splat 路由内的哈希路由时出现问题 (#13108)

完整更新日志: v6.29.0...v6.30.0

v6.29.0

日期: 2025-01-30

次要变更

  • 将请求的 signal 作为参数提供给 patchRoutesOnNavigation (#12900)
    • 如果进行中的导航/fetcher 被中止,这可以用来中止任何清单(manifest)的获取

补丁变更

  • 在生产构建中不记录 v7 弃用警告 (#12794)
  • 在抛出 data() 结果时正确冒泡标头 (#12845)
  • 通过在可能时跳过冗余的 matchRoutes 调用来优化路由匹配 (#12169)
  • 对于 fetcher 调用,从 patchRoutesOnNavigationpath 参数中剥离搜索参数 (#12899)

完整更新日志: v6.28.2...v6.29.0

v6.28.2

日期: 2025-01-16

补丁变更

  • 修复在未选择加入 future.v7_fetcherPersist 时手动使用 fetcher key 的问题 (#12674)
  • 修复在 fetcher 卸载时数据层中 fetcher 数据清理的问题 (#12674)

完整更新日志: v6.28.1...v6.28.2

v6.28.1

日期: 2024-12-20

补丁变更

  • 允许用户通过将标志设置为 false 来选择不接收 v7 弃用警告 (#12441)

完整更新日志: v6.28.0...v6.28.1

v6.28.0

日期:2024-11-06

变更内容

  • 为准备 v7,我们为您尚未选择加入的任何未来标志添加了弃用警告。请使用这些标志来更好地为最终升级到 v7 做准备。

次要变更

  • 为 v7 标志记录弃用警告 (#11750)
    • json/defer 添加弃用警告,推荐返回原始对象
      • 这些方法将在 React Router v7 中被移除

补丁变更

  • 更新 JSDoc URL 以适应新的网站结构(添加 /v6/ 段) (#12141)

完整更新日志: v6.27.0...v6.28.0

v6.27.0

日期:2024-10-11

变更内容

稳定的 API

此版本为即将发布的 React Router v7(参见待定,更多信息请见这些文章)稳定了一批“不稳定”的 API

  • unstable_dataStrategydataStrategy (createBrowserRouter 及其相关函数) (文档)
  • unstable_patchRoutesOnNavigationpatchRoutesOnNavigation (createBrowserRouter 及其相关函数) (文档)
  • unstable_flushSyncflushSync (useSubmit, fetcher.load, fetcher.submit) (文档)
  • unstable_viewTransitionviewTransition (<Link>, <Form>, useNavigate, useSubmit) (文档)

次要变更

  • 稳定导航和 fetchers 的 unstable_flushSync 选项 (#11989)
  • 稳定导航的 unstable_viewTransition 选项和相应的 unstable_useViewTransitionState 钩子 (#11989)
  • 稳定 unstable_dataStrategy (#11974)
  • 稳定 unstable_patchRoutesOnNavigation (#11973)
    • 为方便起见,添加新的 PatchRoutesOnNavigationFunctionArgs 类型 (#11967)

补丁变更

  • 修复在先前提交中已存在 ?index 参数时,提交到当前上下文路由(带有 index 子路由的父路由)的 bug (#12003)
  • 修复 useFormAction 的 bug - 当移除 ?index 参数时,它不会保留其他非 Remix 的 index 参数 (#12003)
  • 修复 fetchers 在并发获取期间通过重定向不保留 preventScrollReset 的 bug (#11999)
  • 避免因连续的重新验证调用导致 fetcher 中止时出现不必要的 console.error (#12050)
  • 修复使用 partialHydration 进行水合时出现错误的 bug (#12070)
  • 移除内部缓存以修复被中断的 patchRoutesOnNavigation 调用的问题 (#12055)
    • ⚠️ 如果您依赖于 unstable_ API 中的此行为,这可能是一个破坏性变更
    • 我们过去在内部缓存进行中的 patchRoutesOnNavigation 调用,以便具有相同起点/终点的多个导航只执行一次函数并使用相同的 promise
    • 然而,这种方法与导航被中断(且 request.signal 中止)时 patch 的短路行为相冲突,因为第一次调用的 patch 会无操作
    • 这个缓存也对有效的缓存键做了一些假设 - 并且对可能发生的任何其他应用状态变化一无所知
    • 因此,缓存已被移除,因为在*大多数*情况下,对诸如 import() 之类的异步路由的重复调用已经自动缓存了 - 如果没有,用户在用户空间实现这个缓存也很容易
  • unstable_patchRoutesOnNavigation 移除内部 discoveredRoutes FIFO 队列 (#11977)
    • ⚠️ 如果您依赖于 unstable_ API 中的此行为,这可能是一个破坏性变更
    • 这最初是作为一种优化实现的,但事实证明它有些过于限制
    • 如果您需要这种优化,您可以在 patchRoutesOnNavigation 内部实现自己的缓存
  • 修复 PatchRoutesOnNavigationFunctionpatch 方法中 RouteObject 的类型,使其不期望传递给 patch 的是与平台无关的路由对象 (#11967)
  • 将从 patchRoutesOnNavigation 抛出的错误直接暴露给 useRouteError,而不是将它们包装在 400 ErrorResponse 实例中 (#12111)

完整更新日志: v6.26.2...v6.27.0

v6.26.2

日期:2024-09-09

补丁变更

  • 更新 unstable_dataStrategy API 以允许更高级的实现 (#11943)
    • ⚠️ 如果您已经采用了 unstable_dataStrategy,请仔细审查,因为这包括对此 API 的破坏性变更
    • unstable_HandlerResult 重命名为 unstable_DataStrategyResult
    • unstable_dataStrategy 的返回签名从一个与 matches 平行的 unstable_DataStrategyResult[] 数组更改为一个键/值对象 routeId => unstable_DataStrategyResult
      • 这允许对重新验证行为进行更高级的控制,因为您可以选择加入或退出重新验证默认情况下可能不会重新验证的数据(通过 match.shouldLoad
    • 您现在应该从您的 handlerOverride 返回/抛出一个结果,而不是返回一个 DataStrategyResult
      • 您的 handlerOverride 的返回值(或抛出的错误)将被包装成一个 DataStrategyResult 并从 match.resolve 返回
      • 因此,如果您正在将 match.resolve() 的结果聚合到一个最终的结果对象中,您应该不需要考虑 DataStrategyResult 类型
      • 如果您正在从您的 handlerOverride 内部手动填充结果对象,那么您需要分配一个 DataStrategyResult 作为值,以便 React Router 知道它是一个成功的执行还是一个错误(详见文档中的示例)
    • unstable_dataStrategy 添加了一个新的 fetcherKey 参数,以允许区分导航调用和 fetcher 调用
  • 在重定向时保留已选择加入的视图过渡 (#11925)
  • 在路由重新验证调用期间保留待处理的视图过渡 (#11917)
  • 修复在快速/同步调用 blocker.proceed 时的阻塞器用法 (#11930)

完整更新日志: v6.26.1...v6.26.2

v6.26.1

日期:2024-08-15

补丁变更

  • unstable_patchRoutesOnMiss 重命名为 unstable_patchRoutesOnNavigation 以匹配新行为 (#11888)
  • 更新 unstable_patchRoutesOnNavigation 逻辑,以便在匹配到带有动态参数或 splat 段的路由时调用该方法,以防存在我们尚未发现的更高得分的静态路由 (#11883)
    • 我们现在还利用一个内部的 FIFO 队列,记录之前已经调用过 unstable_patchRoutesOnNavigation 的路径,这样我们就不会在后续导航到相同路径时重复调用

完整更新日志: v6.26.0...v6.26.1

v6.26.0

日期:2024-08-01

次要变更

  • 添加一个新的 replace(url, init?) 作为 redirect(url, init?) 的替代方案,它在客户端导航重定向上执行 history.replaceState 而不是 history.pushState (#11811)
  • 为 Remix Single Fetch 添加一个新的 unstable_data() API (#11836)
    • 此 API 不适用于在 React Router SPA 应用中直接使用
    • 它主要用于 createStaticHandler.query(),允许 loaders/actions 返回任意数据以及自定义的 status/headers,而无需强制将数据序列化为 Response 实例
    • 这允许通过 unstable_dataStrategy 进行更高级的序列化策略,例如在 Remix Single Fetch 中通过 turbo-stream 进行序列化
    • ⚠️ 这将从 HandlerResult 中移除 status 字段
      • 如果您需要从 unstable_dataStrategy 返回特定的 status,您应该改为通过 unstable_data() 来实现

补丁变更

  • 修复被中断的 fetcher 的内部清理,以避免在导航时出现无效的重新验证 (#11839)
  • 修复在使用 future.v7_partialHydrationunstable_patchRoutesOnMiss 时的初始水合行为 (#11838)
    • 在初始水合期间,router.state.matches 现在将包括任何部分匹配,以便我们可以渲染祖先的 HydrateFallback 组件

完整更新日志: v6.25.1...v6.26.0

v6.25.1

日期:2024-07-17

补丁变更

  • 记忆化一些 RouterProvider 内部构件以减少不必要的重新渲染 (#11803)

完整更新日志: v6.25.0...v6.25.1

v6.25.0

日期:2024-07-16

变更内容

稳定的 v7_skipActionErrorRevalidation

此版本将 future.unstable_skipActionErrorRevalidation 标志稳定为 future.v7_skipActionErrorRevalidation,为即将到来的 React Router v7 版本做准备。

  • 当启用此标志时,返回/抛出 4xx/5xx Response 的 action 默认将不会触发重新验证
  • 这也将 shouldRevalidateunstable_actionStatus 参数稳定为 actionStatus

次要变更

  • future.unstable_skipActionErrorRevalidation 稳定为 future.v7_skipActionErrorRevalidation (#11769)

补丁变更

  • 修复回归并正确解码 useMatch 内的路径,以便匹配/参数反映解码后的参数 (#11789)
  • 修复从 unstable_patchRoutesOnMiss 抛出的错误的冒泡问题 (#11786)
  • 修复使用 unstable_patchRoutesOnMiss 且在服务器上匹配到 splat 路由的 SSR 应用的水合问题 (#11790)

完整更新日志: v6.24.1...v6.25.0

v6.24.1

日期:2024-07-03

补丁变更

  • 从警告消息中移除 polyfill.io 的引用,因为该域名已被出售,并被确定为提供恶意软件 (#11741)
  • 导出 NavLinkRenderProps 类型,以便于为自定义 NavLink 回调进行类型定义 (#11553)
  • 在使用 future.v7_relativeSplatPath 时,正确解析作为无路径路由子路由的 splat 路由中的相对路径 (#11633)
  • 战争迷雾 (不稳定):在路由修补期间触发新的 router.routes 身份/重排 (#11740)
  • 战争迷雾 (不稳定):修复当 splat 路由匹配时的初始匹配问题 (#11759)

完整更新日志: v6.24.0...v6.24.1

v6.24.0

日期:2024-06-24

变更内容

惰性路由发现(又名“战争迷雾”)

我们非常激动地在 v6.24.0 中发布我们新的“惰性路由发现”API!有关一些背景信息,请查看原始的 RFC简而言之,自从我们在 v6.4 中通过 <RouterProvider> 引入了数据 API 以来,我们一直对其中一个权衡感到有些失望,那就是缺乏一个引人注目的代码分割方案,这与我们在 <BrowserRouter>/<Routes> 应用中所拥有的方案相呼应。我们在 v6.9.0 中通过 route.lazy 向改进这一方案迈出了一小步,但在 v6.24.0 中我们已经走完了剩下的路。

通过“战争迷雾”,您现在可以通过传递给 createBrowserRouter(及其 memory/hash 对应物)的新的 unstable_patchRoutesOnMiss 选项来惰性加载路由树的部分。这为您提供了一种方法,可以在 React Router 无法匹配给定路径时介入,并在导航(或 fetcher 调用)期间向路由树中修补新的路由。

这是一个非常小的例子,但请参考文档获取更多信息和用例

const router = createBrowserRouter(
  [
    {
      id: "root",
      path: "/",
      Component: RootComponent,
    },
  ],
  {
    async unstable_patchRoutesOnMiss({ path, patch }) {
      if (path === "/a") {
        // Load the `a` route (`{ path: 'a', Component: A }`)
        let route = await getARoute();
        // Patch the `a` route in as a new child of the `root` route
        patch("root", [route]);
      }
    },
  },
);

次要变更

  • 添加对惰性路由发现(又名“战争迷雾”)的支持 (#11626)

补丁变更

  • 修复 fetcher.submit 类型 - 移除不正确的 navigate/fetcherKey/unstable_viewTransition 选项,因为它们仅与 useSubmit 相关 (#11631)
  • 允许传递给 <StaticRouter>location.state 值为假值 (#11495)

完整更新日志: v6.23.1...v6.24.0

v6.23.1

日期:2024-05-10

补丁变更

  • 允许 undefined 通过 <Await> 解析 (#11513)
  • 在检查 document.startViewTransition 可用性时添加防御性的 document 检查 (#11544)
  • react-router-dom/server 的导入改回 react-router-dom 而不是 index.ts (#11514)
  • @remix-run/router - 在 staticHandler.queryRoute 上支持 unstable_dataStrategy (#11515)

完整更新日志: v6.23.0...v6.23.1

v6.23.0

日期:2024-04-23

变更内容

数据策略 (不稳定)

新的 unstable_dataStrategy API 是一个低级 API,专为高级用例设计,在这些用例中,您需要控制 loader/action 函数的数据策略。默认实现是当前的行为,即并行获取所有 loader,但此选项允许用户实现更高级的数据流,包括 Remix 的“单一获取”、用户空间中间件/上下文 API、自动 loader 缓存等。请参阅文档获取更多信息。

注意: 这是一个专为高级用例设计的低级 API。它会覆盖 React Router 内部对 loader/action 执行的处理,如果操作不当,将会破坏您的应用代码。请谨慎使用并进行适当的测试。

跳过 Action 错误重新验证 (不稳定)

目前,在任何 action 提交后,所有活动的 loader 都会重新验证,无论 action 的结果如何。然而,在大多数情况下,来自 action4xx/5xx 响应意味着没有数据实际更改,重新验证是不必要的。我们引入了一个新的 future.unstable_skipActionErrorRevalidation 标志来改变这里的行为,并计划在未来版本的 React Router 中将其设为默认行为。

启用此标志后,返回/抛出 4xx/5xx 响应状态的 action 将不再自动重新验证。如果您需要在启用此标志的情况下在 4xx/5xx 结果后重新验证,您仍然可以通过从 shouldRevalidate 返回 true 来实现——该函数现在还收到了一个新的 unstable_actionStatus 参数以及 actionResult,这样您就可以根据 action 响应的状态做出决策,而无需将其编码到 action 数据中。

次要变更

  • 添加一个新的 unstable_dataStrategy 配置选项 (#11098, #11377)
  • @remix-run/router - 添加一个新的 future.unstable_skipActionRevalidation 未来标志 (#11098)
  • @remix-run/router - SSR:向 staticHandler.query 方法添加了一个新的 skipLoaderErrorBubbling 选项,以禁用静态处理器对错误的冒泡,用于 Remix 的单一获取实现 (#11098, (#11377))

完整更新日志: v6.22.3...v6.23.0

v6.22.3

日期:2024-03-07

补丁变更

  • 修复一个 future.v7_partialHydration 的 bug,该 bug 会在 SSR 加载器错误冒泡到父边界时,在水合时重新运行边界下的加载器 (#11324)
  • 修复一个 future.v7_partialHydration 的 bug,该 bug 会在路由没有加载器时认为路由器未初始化 (#11325)

完整更新日志: v6.22.2...v6.22.3

v6.22.2

日期:2024-02-28

补丁变更

  • 在部分水合运行时保留已水合的错误 (#11305)

完整更新日志: v6.22.1...v6.22.2

v6.22.1

日期:2024-02-16

补丁变更

  • 修复预编码动态参数值的编码/解码问题 (#11199)

完整更新日志: v6.22.0...v6.22.1

v6.22.0

日期:2024-02-01

变更内容

核心 Web 指标技术报告标志

2021年,HTTP Archive 推出了核心 Web 指标技术报告仪表板

通过结合 Chrome 用户体验报告 26 (CrUX) 数据集中的真实用户体验和 HTTP Archive 30 中的 Web 技术检测,我们可以窥见架构决策(如选择 CMS 平台或 JavaScript 框架)如何在网站的 CWV 性能中发挥作用。

他们使用一个名为 wappalyzer 的工具,通过查找特定的脚本、全局 JS 变量或其他识别特征来识别给定网站正在使用的技术。例如,对于 Remix 应用程序,他们查找全局 __remixContext 变量来识别网站正在使用 Remix。

我们注意到,React Router 无法被可靠地识别,因为没有识别性的全局特征。他们目前正在寻找名称中带有 react-router 的外部脚本。这将识别出使用 CDN(如 unpkg)的 React Router 网站——但这将错过从 npm 注册表安装 React Router 并将其捆绑到 JS 文件中的**绝大多数**网站。这导致了对 React Router 在 Web 上使用情况的严重低估

6.22.0 版本开始,使用 react-router-dom 的网站将开始添加一个 window.__reactRouterVersion 变量,该变量将被设置为 SemVer 主要版本号的字符串值(即 window.__reactRouterVersion = "6";),以便它们可以被正确识别。

次要变更

  • 为 CWV 报告检测包含 window.__reactRouterVersion (#11222)
  • 添加一个 createStaticHandlerfuture.v7_throwAbortReason 标志,以便在请求被中止时抛出 request.signal.reason(默认为 DOMException),而不是一个 Error,例如 new Error("query() call aborted: GET /path") (#11104)
    • 请注意,DOMException 是在 Node v17 中添加的,因此在 Node 16及以下版本中您不会得到 DOMException

补丁变更

  • 如果传递给 getStaticContextFormError 的是 ErrorResponse,则尊重其状态码 (#11213)

完整更新日志: v6.21.3...v6.22.0

v6.21.3

日期:2024-01-18

补丁变更

  • 修复在使用 basenameNavLinkisPending 问题 (#11195)
  • Blocker/BlockerFunction 类型中移除残留的 unstable_ 前缀 (#11187)

完整更新日志: v6.21.2...v6.21.3

v6.21.2

日期:2024-01-11

补丁变更

  • 在可用时,为内部 fetcher 键利用 useId (#11166)
  • 修复动态参数名称中未捕获破折号的 bug (#11160)
  • 不要尝试反序列化空的 JSON 响应 (#11164)

完整更新日志: v6.21.1...v6.21.2

v6.21.1

日期:2023-12-21

补丁变更

  • 修复在指定 v7_partialHydration 时,route.lazy 在初始 SPA 加载时无法正常工作的 bug (#11121)
  • 修复在 submitting 阶段卸载的持久化 fetchers 无法触发重新验证的 bug (#11102)
  • resolveTo 中去重相对路径逻辑 (#11097)

完整更新日志: v6.21.0...v6.21.1

v6.21.0

日期:2023-12-13

变更内容

future.v7_relativeSplatPath

我们在 6.19.0 中修复了一个 splat 路由路径解析的 bug,但后来发现大量应用程序依赖于这个有 bug 的行为,所以我们在 6.20.1 中撤销了修复(参见 #10983, #11052, #11078)。

这个有 bug 的行为是,在解析 splat 路由内的相对路径时,默认行为会*忽略*当前路由路径的任何 splat (*) 部分。当启用未来标志时,splat 部分会包含在 splat 路由内的相对路径逻辑中。

更多信息,请参阅 useResolvedPath 文档 和/或 详细的更新日志条目

部分水合

我们为 @remix-run/router 添加了一个新的 future.v7_partialHydration 未来标志,它在服务器端渲染时启用数据路由器的部分水合。这允许您提供 hydrationData.loaderData,其中包含*一些*初始匹配的路由加载器的数据,但不是全部。当启用此标志时,路由器将在 router.initialize() 期间为没有水合加载器数据的路由调用 loader 函数,并且在执行未水合的路由时,它将渲染到最深层提供的 HydrateFallback(直到第一个没有水合数据的路由)。 (#11033)

次要变更

  • 添加一个新的 future.v7_relativeSplatPath 标志,以实现一个对 splat 路由内相对路由的破坏性 bug 修复。 (#11087)
  • 添加一个新的 future.v7_partialHydration 未来标志,该标志在服务器端渲染时启用数据路由器的部分水合 (#11033)

补丁变更

  • ErrorBoundary 中正确处理假值错误 (#11071)
  • 捕获并冒泡从 loader/action 函数中解包响应时抛出的错误 (#11061)
  • 修复在匹配路由之外渲染 Link/NavLink 时的 relative="path" 问题 (#11062)

完整更新日志: v6.20.1...v6.21.0

v6.20.1

日期:2023-12-01

补丁变更

  • 由于大量应用程序依赖于有 bug 的行为,撤销了对 splat 路由的 useResolvedPath 修复(参见 #11052) (#11078)
    • 我们计划在下一个次要版本中通过一个未来标志重新引入这个修复(参见此评论
    • 此修复包含在 6.19.06.20.0 版本中。如果您从 6.18.0 或更早版本升级,您将不会受到此修复的影响。

完整更新日志: v6.20.0...v6.20.1

v6.20.0

日期:2023-11-22

[!WARNING] 请使用 6.20.1 或更高版本,而不是 6.20.0。我们发现大量应用依赖于此版本中修复的一个有 bug 的行为 (#11045)。我们在 6.20.1 中撤销了该修复,并将在后续版本中通过一个未来标志重新引入。详情请见 #11052

次要变更

  • 从公共 API 导出 PathParam 类型 (#10719)

补丁变更

  • 当启用 v7_fetcherPersist 时,不要重新验证未挂载的 fetchers (#11044)
  • 修复 splat 路由中 resolveTo 路径解析的 bug (#11045)
    • 这是对 #10983 的跟进,以处理使用 getPathContributingMatches 的其他几个代码路径
    • 这从 @remix-run/router 中移除了 UNSAFE_getPathContributingMatches 导出,因为我们不再需要在 react-router/react-router-dom 层中使用它

完整更新日志: v6.19.0...v6.20.0

v6.19.0

日期:2023-11-16

[!WARNING] 请使用 6.20.1 或更高版本,而不是 6.19.0。我们发现大量应用依赖于此版本中修复的一个有 bug 的行为 (#10983)。我们在 6.20.1 中撤销了该修复,并将在后续版本中通过一个未来标志重新引入。详情请见 #11052

变更内容

unstable_flushSync API

此版本为命令式 API(useSubmit, useNavigate, fetcher.submit, fetcher.load)带来了新的 unstable_flushSync 选项,让用户可以选择为待处理/乐观 UI 启用同步 DOM 更新。

function handleClick() {
  submit(data, { flushSync: true });
  // Everything is flushed to the DOM so you can focus/scroll to your pending/optimistic UI
  setFocusAndOrScrollToNewlyAddedThing();
}

次要变更

  • useNavigate/useSubmit/fetcher.load/fetcher.submit 添加 unstable_flushSync 选项,以选择不使用 React.startTransition,而使用 ReactDOM.flushSync 进行状态更新 (#11005)
  • useBlocker 钩子中移除 unstable_ 前缀,因为它已经使用了足够长的时间,我们对该 API 很有信心 (#10991)
    • 由于浏览器处理 window.confirm 的方式存在差异,导致 React Router 无法保证一致/正确的行为,我们不打算从 unstable_usePrompt 中移除该前缀

补丁变更

  • 修复 useActionData,使其返回正确的上下文 action 数据,而不是树中的*任何* action 数据 (#11023)

  • 修复 useResolvedPath 中的一个 bug,该 bug 会导致 splat 路由中的 useResolvedPath(".") 丢失 URL 路径的 splat 部分。 (#10983)

    • ⚠️ 这修复了一个相当长期的 bug,特别是针对 splat 路由内的 "." 路径,该路径错误地丢弃了 URL 的 splat 部分。如果您在应用程序的 splat 路由内通过 "." 进行相对路由,您应该仔细检查您的逻辑是否不依赖于这个有 bug 的行为,并相应地进行更新。
  • 修复了一个问题,即在保持挂载的 useFetcher 中更改 fetcher 的 key 没有被检测到 (#11009)

  • 修复 useFormAction,它错误地从子路由的 action 提交中继承了 ?index 查询参数 (#11025)

  • 修复当 to 位置有尾部斜杠时 NavLinkactive 逻辑 (#10734)

  • 修复类型,使 unstable_usePrompt 除了 boolean 之外,还可以接受一个 BlockerFunction (#10991)

  • 修复 relative="path" 的 bug,其中相对路径计算从完整的位置路径名开始,而不是从当前的上下文路由路径名开始。 (#11006)

    <Route path="/a">
      <Route path="/b" element={<Component />}>
        <Route path="/c" />
      </Route>
    </Route>;
    
    function Component() {
      return (
        <>
          {/* This is now correctly relative to /a/b, not /a/b/c */}
          <Link to=".." relative="path" />
          <Outlet />
        </>
      );
    }
    

完整更新日志: 6.18.0...6.19.0

v6.18.0

日期:2023-10-31

变更内容

新的 Fetcher API

根据这个 RFC,我们引入了一些新的 API,让您能够更精细地控制您的 fetcher 行为。

  • 您现在可以通过 useFetcher({ key: string }) 指定您自己的 fetcher 标识符,这允许您从应用程序中的不同组件访问相同的 fetcher 实例,而无需通过 props 传递
  • Fetcher 的 key 现在暴露在 useFetchers 返回的 fetchers 上,以便可以通过 key 查找它们
  • FormuseSubmit 现在支持可选的 navigate/fetcherKey props/params,以允许在后台启动一个 fetcher 提交,并带有可选的用户指定的 key
    • <Form method="post" navigate={false} fetcherKey="my-key">
    • submit(data, { method: "post", navigate: false, fetcherKey: "my-key" })
    • 以这种方式调用 fetcher 是短暂且无状态的
    • 如果您需要访问这些 fetcher 之一的状态,您将需要利用 useFetchers()useFetcher({ key }) 在其他地方查找它

持久化未来标志 (future.v7_fetcherPersist)

根据与上述相同的 RFC,我们引入了一个新的 future.v7_fetcherPersist 标志,它允许您选择加入新的 fetcher 持久化/清理行为。fetchers 不再在卸载时立即被清理,而是会持续存在直到它们返回到 idle 状态。这使得在原始 fetcher 需要卸载的场景中,实现待定/乐观 UI 变得*非常*容易。

  • 这在某种程度上是一个长期的 bug 修复,因为 useFetchers() API 本来应该只反映**进行中**的 fetcher 信息,用于待定/乐观 UI——它不是为了反映 fetcher 数据或在 fetcher 返回到 idle 状态后还保留它们
  • 在选择加入此标志时,请留意以下具体的行为变化,并检查您的应用程序的兼容性
    • 在*仍然挂载时*完成的 Fetchers 在完成后将不再出现在 useFetchers() 中 - 它们在那里没有任何作用,因为您可以通过 useFetcher().data 访问数据
    • 以前在*进行中*卸载的 Fetchers 将不会立即被中止,而是会在它们返回到 idle 状态后被清理
      • 它们在进行中时仍会通过 useFetchers 暴露,因此您在卸载后仍然可以访问待定/乐观数据
      • 如果一个 fetcher 在完成时不再挂载,那么它的结果将不会被后处理——例如,重定向将不会被遵循,错误也不会在 UI 中冒泡
      • 然而,如果一个 fetcher 在树的其他地方使用相同的 key 被重新挂载,那么它的结果将被处理,即使原始的 fetcher 已经被卸载

次要变更

  • 添加 fetcher key API 和 navigate=false 选项 (#10960)
  • 添加 future.v7_fetcherPersist 标志 (#10962)
  • matchPath 中添加对可选路径段的支持 (#10768)

补丁变更

  • 修复 BrowserRouterHashRouterMemoryRouter 上的 future 属性,使其接受 Partial<FutureConfig>,而不是要求包含所有标志 (#10962)
  • 修复 router.getFetcher/router.deleteFetcher 类型定义,它们错误地将 key 指定为可选参数 (#10960)

完整更新日志: 6.17.0...6.18.0

v6.17.0

日期:2023-10-16

变更内容

视图过渡 🚀

我们很高兴在 React Router 中发布对 视图过渡 API 的实验性支持!您现在可以触发导航性 DOM 更新,将其包装在 document.startViewTransition 中,从而在您的应用程序的 SPA 导航中启用 CSS 动画过渡。

在您的 React Router 应用中启用视图过渡的最简单方法是通过新的 <Link unstable_viewTransition> 属性。这将导致导航 DOM 更新被包装在 document.startViewTransition 中,从而为 DOM 更新启用过渡。没有任何额外的 CSS 样式,您将为您的页面获得一个基本的交叉淡入淡出动画。

如果您需要为您的动画应用更精细的样式,您可以利用 unstable_useViewTransitionState 钩子,它会告诉您过渡何时正在进行中,您可以用它来应用类或样式

function ImageLink(to, src, alt) {
  const isTransitioning = unstable_useViewTransitionState(to);
  return (
    <Link to={to} unstable_viewTransition>
      <img
        src={src}
        alt={alt}
        style={{
          viewTransitionName: isTransitioning ? "image-expand" : "",
        }}
      />
    </Link>
  );
}

您也可以使用 <NavLink unstable_viewTransition> 简写,它将为您管理钩子的使用,并在过渡期间自动向 <a> 添加一个 transitioning

a.transitioning img {
  view-transition-name: "image-expand";
}
<NavLink to={to} unstable_viewTransition>
  <img src={src} alt={alt} />
</NavLink>

有关视图过渡的用法示例,请查看我们对超棒的 Astro Records 演示的复刻

有关使用视图过渡 API 的更多信息,请参阅 Google Chrome 团队的使用视图过渡 API 实现平滑简单的过渡指南。

次要变更

  • 添加对视图过渡的支持 (#10916)

补丁变更

  • sessionStorage 不可用时,在 ScrollRestoration 中记录警告并优雅地失败 (#10848)
  • 修复 RouterProviderfuture 属性类型为 Partial<FutureConfig>,这样就不必指定所有标志 (#10900)
  • 如果路径包含 URL 段,允许 404 检测利用根路由错误边界 (#10852)
  • 修复 ErrorResponse 类型以避免泄漏内部字段 (#10876)

完整更新日志: 6.16.0...6.17.0

v6.16.0

日期:2023-09-13

次要变更

  • 为了在未来实现更严格的 TypeScript 支持,我们的目标是将当前暴露的用户提供数据的类型中的 any 替换为 unknown。为了在 Remix v2 中做到这一点而不引入 React Router v6 的破坏性变更,我们为一些共享类型添加了泛型。这些在 React Router 中继续默认为 any,并在 Remix 中被 unknown 覆盖。在 React Router v7 中,我们计划将这些作为破坏性变更移动到 unknown。 (#10843)
    • Location 现在接受一个泛型用于 location.state
    • ActionFunctionArgs/ActionFunction/LoaderFunctionArgs/LoaderFunction 现在接受一个泛型用于 context 参数(仅在通过 createStaticHandler 的 SSR 用法中使用)
    • useMatches 的返回类型(现在导出为 UIMatch)接受 match.datamatch.handle 的泛型 - 这两者都已经设置为 unknown
  • @private 类导出 ErrorResponse 移动到 UNSAFE_ErrorResponseImpl 导出,因为它是一个实现细节,用户不应构造 ErrorResponse 实例。这使我们可以导出一个 type ErrorResponse,它通过 InstanceType 与类的实例相关联。用户代码只应将 ErrorResponse 用作类型,并应通过 isRouteErrorResponse 进行类型收窄。 (#10811)
  • 导出 ShouldRevalidateFunctionArgs 接口 (#10797)
  • 移除了仅为 Remix v1 向后兼容层所需且在 Remix v2 中不再需要的私有/内部 API (_isFetchActionRedirect, _hasFetcherDoneAnything) (#10715)

补丁变更

  • 在服务器渲染中正确编码渲染的 URI 以避免水合错误 (#10769)
  • 向被中止的 query/queryRoute 调用的错误消息中添加方法/URL (#10793)
  • 修复 route.lazy 路由上 loader/action 抛出错误的竞争条件问题 (#10778)
  • 修复传递给 shouldRevalidate 的参数对象中 actionResult 的类型 (#10779)

完整更新日志: v6.15.0...v6.16.0

v6.15.0

日期:2023-08-10

次要变更

  • 添加了一个新的 redirectDocument() 函数,它允许用户指定来自 loader/action 的重定向应该触发文档重新加载(通过 window.location),而不是尝试通过 React Router 导航到重定向的位置 (#10705)

补丁变更

  • 如果重新验证没有主动发生,确保 useRevalidator 在重新渲染之间保持引用稳定 (#10707)
  • 确保哈希历史记录的哈希路径名始终以斜杠开头 (#10753)
  • 修复了影响 Firefox 中使用 URLSearchParamsuseSearchParams 钩子的 Web 扩展的一个边缘情况 (#10620)
  • 重新排列 unstable_usePrompt 中的 effect 顺序,以避免在提示被解除阻塞且同步执行导航时抛出异常 (#10687, #10718)
  • SSR:对于未指定 action 的情况,不要在 useFormAction() 中包含哈希值,因为它无法在服务器上确定,并会导致水合问题 (#10758)
  • SSR:修复了 queryRoute 中一个不总能识别抛出的 Response 实例的问题 (#10717)
  • react-router-native:将 @ungap/url-search-params 依赖从 ^0.1.4 更新到 ^0.2.2 (#10590)

完整更新日志v6.14.2...v6.15.0

v6.14.2

日期:2023-07-17

补丁更新

  • <Form> 添加缺失的 state 属性,以便在提交导航时填充 history.state (#10630)
  • 如果 defer 的 promise 解析/拒绝为 undefined,则触发错误,以匹配 loader 和 action 必须返回值或 null 的行为 (#10690)
  • 正确处理被常规导航中断的 fetcher 重定向 (#10674)
  • 初始加载的 fetcher 不应在 GET 导航时自动重新验证 (#10688)
  • 通过 <ScrollRestoration> 模拟哈希滚动时,正确解码元素 ID (#10682)
  • Typescript:增强 Route.lazy 的返回类型,禁止返回空对象 (#10634)
  • SSR:支持对 Error 的子类(如 ReferenceError/TypeError)进行正确的水合 (#10633)

完整更新日志v6.14.1...v6.14.2

v6.14.1

日期:2023-06-30

补丁更新

  • 修复了当 unstable_useBlocker 与不稳定的阻塞函数一起使用时出现的循环问题 (#10652)
  • 修复了在后续导航中重用阻塞器的问题 (#10656)
  • 依赖更新
    • @remix-run/router@1.7.1

完整更新日志v6.14.0...v6.14.1

v6.14.0

日期:2023-06-23

更新内容

JSON/Text 提交

6.14.0 版本通过 useSubmit/fetcher.submit 增加了对 JSON 和 Text 提交的支持,因为如果您在客户端 SPA 中工作,不总是方便地需要序列化为 FormData。要选择使用这些编码,您只需指定正确的 formEncType

选择使用 application/json 编码

function Component() {
  let navigation = useNavigation();
  let submit = useSubmit();
  submit({ key: "value" }, { method: "post", encType: "application/json" });
  // navigation.formEncType => "application/json"
  // navigation.json        => { key: "value" }
}

async function action({ request }) {
  // request.headers.get("Content-Type") => "application/json"
  // await request.json()                => { key: "value" }
}

选择使用 text/plain 编码

function Component() {
  let navigation = useNavigation();
  let submit = useSubmit();
  submit("Text submission", { method: "post", encType: "text/plain" });
  // navigation.formEncType => "text/plain"
  // navigation.text        => "Text submission"
}

async function action({ request }) {
  // request.headers.get("Content-Type") => "text/plain"
  // await request.text()                => "Text submission"
}

⚠️ v7 版本中默认行为将发生变化

请注意,为避免重大变更,默认行为仍会将简单的键/值 JSON 对象编码为 FormData 实例。

function Component() {
  let navigation = useNavigation();
  let submit = useSubmit();
  submit({ key: "value" }, { method: "post" });
  // navigation.formEncType => "application/x-www-form-urlencoded"
  // navigation.formData    => FormData instance
}

async function action({ request }) {
  // request.headers.get("Content-Type") => "application/x-www-form-urlencoded"
  // await request.formData()            => FormData instance
}

此行为很可能会在 v7 中改变,因此最好通过 formEncType: "application/x-www-form-urlencoded"formEncType: "application/json" 明确指定任何 JSON 对象提交,以便您最终顺利迁移到 v7。

次要更新

  • useSubmit/fetcher.submit 添加对 application/jsontext/plain 编码的支持。为了反映这些额外的类型,useNavigation/useFetcher 现在也包含 navigation.json/navigation.textfetcher.json/fetcher.text,其中包含适用的 json/text 提交数据。 (#10413)

补丁更新

  • 在现代浏览器(支持新的 submitter 参数的浏览器)中,当从 submitter 元素提交表单时,优先使用内置的 new FormData(form, submitter),而不是之前的手动方法 (#9865)
    • 对于不支持的浏览器,我们继续将提交按钮的条目附加到末尾,并且还为 type="image" 按钮添加了基本支持。
    • 如果开发人员希望为旧版浏览器提供完全符合规范的支持,他们可以使用 formdata-submitter-polyfill
  • 在更新 React Router 状态*之前*调用 window.history.pushState/replaceState(而不是之后),以便在同步的 React 17 渲染期间 window.locationuseLocation 匹配 (#10448)
    • ⚠️ 注意:通常应用程序不应依赖 window.location,而应尽可能引用 useLocation,因为 window.location 不会 100% 同步(由于 popstate 事件、并发模式等)。
  • 避免为尚未完成数据加载的 fetcher 调用 shouldRevalidate (#10623)
  • 从提供给 <ScrollRestoration getKey>location 中剥离 basename,以匹配 useLocation 的行为 (#10550)
  • 从提供给 unstable_useBlocker 函数的 location 中剥离 basename,以匹配 useLocation 的行为 (#10573)
  • 修复 StrictModeunstable_useBlocker 的 key 问题 (#10573)
  • 修复当传递数值 0 作为参数时 generatePath 的问题 (#10612)
  • 修复 React 17 上 tsc --skipLibCheck:false 的问题 (#10622)
  • typescript 升级到 5.1 (#10581)

完整更新日志v6.13.0...v6.14.0

v6.13.0

日期:2023-06-14

更新内容

6.13.0 本质上是一个补丁发布,但由于我们添加了一个新的未来标志,因此它带有一个 SemVer 的次要版本号提升。

future.v7_startTransition

长话短说6.13.06.12.0 相同,但我们将 React.startTransition 的使用移到了一个可选的 future.v7_startTransition 未来标志 之后,因为我们发现现有的一些应用程序使用的 Suspense 方式与 React.startTransition 不兼容。

因此,在 6.13.0 中,默认行为将不再利用 React.startTransition

<BrowserRouter>
  <Routes>{/*...*/}</Routes>
</BrowserRouter>

<RouterProvider router={router} />

如果您希望启用 React.startTransition,请将未来标志传递给您的路由器组件。

<BrowserRouter future={{ v7_startTransition: true }}>
  <Routes>{/*...*/}</Routes>
</BrowserRouter>

<RouterProvider router={router} future={{ v7_startTransition: true }}/>

我们建议大家尽早采用此标志,以便更好地与 React 并发模式兼容,但如果您遇到问题,可以继续不使用 React.startTransition 直到 v7。问题通常归结为在渲染周期中创建全新的 promise,因此如果您在选择使用 React.startTransition 时遇到问题,您应该将 promise 的创建移出渲染周期或将其置于 useMemo 之后。

次要更新

  • React.startTransition 的使用移至一个未来标志之后 (#10596)

补丁更新

  • 绕过 webpack/terser 在生产模式下对 React.startTransition 的压缩错误 (#10588)

完整更新日志v6.12.1...v6.13.0

v6.12.1

日期:2023-06-08

[!WARNING] 请使用 6.13.0 或更高版本,而不是 6.12.0/6.12.1。这些版本存在一些 Webpack 构建/压缩问题,导致构建失败或在您的生产包中出现无效的压缩代码。更多详情请参见 #10569#10579

补丁更新

  • 调整 React.startTransition 的特性检测,以修复 webpack + react 17 的编译错误 (#10569)

完整更新日志v6.12.0...v6.12.1

v6.12.0

日期:2023-06-06

[!WARNING] 请使用 6.13.0 或更高版本,而不是 6.12.0/6.12.1。这些版本存在一些 Webpack 构建/压缩问题,导致构建失败或在您的生产包中出现无效的压缩代码。更多详情请参见 #10569#10579

更新内容

React.startTransition 支持

6.12.0 版本中,我们通过将内部路由器状态更新包装在 React.startTransition 中,为挂起组件提供了更好的支持。这意味着,例如,如果目标路由中的某个组件挂起,并且您没有提供 Suspense 边界来显示回退 UI,React 将延迟渲染新的 UI,并显示旧的 UI,直到异步操作解决。这对于等待图片或 CSS 文件加载等情况非常有用(技术上讲,您也可以用它来加载数据,但我们仍然推荐使用 loader 😀)。要快速了解此用法,请查看 Ryan 在 Twitter 上的演示

次要更新

  • 使用 React.startTransition 包装内部路由器状态更新 (#10438)

补丁更新

  • 如果提交的 fetcher 被删除,允许 fetcher 的重新验证完成 (#10535)
  • 当尝试使用不可序列化的状态执行 PUSH 导航时,重新抛出 DOMException (DataCloneError)。(#10427)
  • 确保当哈希存在时进行重新验证 (#10516)
  • 升级 jestjsdom (#10453)
  • 依赖更新

完整更新日志v6.11.2...v6.12.0

v6.11.2

日期:2023-05-17

补丁更新

  • 修复在 <RouterProvider> 内的后代 <Routes>basename 重复的问题 (#10492)
  • 修复当哈希存在时,初始数据加载不会启动的错误 (#10493)
  • 导出 SetURLSearchParams 类型 (#10444)
  • 通过在 _internalSetRoutes 中正确重构新路由和 manifest,修复 Remix HMR 驱动的错误边界问题 (#10437)

完整更新日志v6.11.1...v6.11.2

v6.11.1

日期:2023-05-03

补丁更新

  • 修复在后代 <Routes> 中使用 Component API 的问题 (#10434)
  • 修复在 <RouterProvider> 内的 <Routes> 中调用 useNavigate 的错误 (#10432)
  • 修复在使用数据路由器时,在严格模式下使用 <Navigate> 的问题 (#10435)
  • 修复在没有路径的情况下导航时 basename 的处理问题 (#10433)
  • “相同哈希”导航不再重新运行 loader,以匹配浏览器行为(即 /path#hash -> /path#hash)(#10408)

完整更新日志v6.11.0...v6.11.1

v6.11.0

日期:2023-04-28

次要更新

  • useFetcher 中启用 basename 支持 (#10336)
    • 如果您之前通过手动前置 basename 来解决此问题,那么您需要从您的 fetcher 调用中移除手动前置的 basename(例如 fetcher.load('/basename/route') -> fetcher.load('/route')
  • 依赖更新

补丁更新

  • 使用 RouterProvider 时,useNavigate/useSubmit/fetcher.submit 在 location 变化时现在是稳定的,因为我们可以通过 @remix-run/router 实例处理相对路由,从而摆脱了对 useLocation() 的依赖 (#10336)
    • 使用 BrowserRouter 时,这些钩子在 location 变化时仍然不稳定,因为它们仍然依赖 useLocation()
  • Fetcher 不应再因搜索参数变化或路由到相同 URL 而重新验证,仅在 action 提交或 router.revalidate 调用时重新验证 (#10344)
  • 修复在路由定义中使用 Component 而非 element 时导致的意外重新渲染 (#10287)
  • <Link to="//"> 和其他无效 URL 值进行优雅地失败处理 (#10367)
  • <RouterProvider> 中,将内部 @remix-run/router 路由器状态同步从 useSyncExternalStore 切换到 useState。我们发现了一些 细微的 bug,其中路由器状态更新的传播*先于*其他正常的 useState 更新,这可能在 useEffect 调用中导致陷阱。(#10377, #10409)
  • 在开发模式下,将默认错误边界捕获的 loader/action 错误记录到控制台,以便更容易评估堆栈跟踪 (#10286)
  • 修复当 RouterProvider 存在错误时,阻止后代 <Routes> 渲染的 bug (#10374)
  • 通过在 layout effect 中设置 activeRef 来修复渲染周期中 useNavigate 的检测,允许将 navigate 函数传递给子组件并在其 useEffect 中调用 (#10394)
  • 允许 useRevalidator() 解决 loader 驱动的错误边界场景 (#10369)
  • 增强 LoaderFunction/ActionFunction 的返回类型,以防止 undefined 成为有效的返回值 (#10267)
  • 确保对没有 loader 的路由进行 fetcher.load 调用时,返回正确的 404 错误 (#10345)
  • 解耦正在重新验证的 fetcher 与触发它们的事件之间的 AbortController 使用,这样重新验证的 fetcher 的卸载/删除不会影响正在进行的触发导航/重新验证 (#10271)

完整更新日志v6.10.0...v6.11.0

v6.10.0

日期:2023-03-29

更新内容

我们最近在 Remix 博客上发表了一篇题为“为您的 Remix 应用提供未来保障”的文章,其中介绍了我们确保您的 Remix 和 React Router 应用未来能平滑升级的策略。React Router 6.10.0 为数据路由器添加了对这些标志的支持,您可以在创建路由器时指定它们。

const router = createBrowserRouter(routes, {
  future: {
    // specify future flags here
  },
});

您也可以查看文档这里这里

次要更新

future.v7_normalizeFormMethod

引入的第一个未来标志是 future.v7_normalizeFormMethod,它将把暴露的 useNavigation()/useFetcher() formMethod 字段规范化为大写的 HTTP 方法,以与 fetch()(以及一些 Remix)的行为保持一致。(#10207)

  • future.v7_normalizeFormMethod 未指定或设置为 false(v6 默认行为)时,
    • useNavigation().formMethod 是小写
    • useFetcher().formMethod 是小写
  • future.v7_normalizeFormMethod === true
    • useNavigation().formMethod 是大写
    • useFetcher().formMethod 是大写

补丁更新

  • 修复 createStaticHandler,使其除了检查 errorElement 外,还检查路由上的 ErrorBoundary (#10190)
  • 修复在 createRoutesFromElements 中使用 Fragments 时的路由 ID 生成问题 (#10193)
  • 如果 fetcher 的 action 重定向,则向 shouldRevalidate 提供 fetcher 提交信息 (#10208)
  • 在路由器初始化期间正确处理 lazy() 错误 (#10201)
  • 移除对 DeferredDatainstanceof 检查,以适应 SSR 打包场景中的 ESM/CJS 边界问题 (#10247)
  • 更新至最新的 @remix-run/web-fetch@4.3.3 (#10216)

完整更新日志v6.9.0...v6.10.0

v6.9.0

日期:2023-03-10

更新内容

Component/ErrorBoundary 路由属性

React Router 现在支持一种替代方式来定义路由的 elementerrorElement 字段,即使用 React 组件而非 React 元素。您可以选择将 React 组件传递给新的 ComponentErrorBoundary 字段。两者在功能上没有区别,所以请使用您喜欢的方式 😀。您不应该同时定义两者,但如果这样做了,Component/ErrorBoundary 将会“获胜”。

JSON 语法示例

// Both of these work the same:
const elementRoutes = [{
  path: '/',
  element: <Home />,
  errorElement: <HomeError />,
}]

const componentRoutes = [{
  path: '/',
  Component: Home,
  ErrorBoundary: HomeError,
}]

function Home() { ... }
function HomeError() { ... }

JSX 语法示例

// Both of these work the same:
const elementRoutes = createRoutesFromElements(
  <Route path='/' element={<Home />} errorElement={<HomeError /> } />
);

const componentRoutes = createRoutesFromElements(
  <Route path='/' Component={Home} ErrorBoundary={HomeError} />
);

function Home() { ... }
function HomeError() { ... }

引入懒加载路由模块

为了保持您的应用程序包足够小并支持路由的代码分割,我们引入了一个新的 lazy() 路由属性。这是一个异步函数,它会解析您路由定义中非路由匹配的部分(loader, action, element/Component, errorElement/ErrorBoundary, shouldRevalidate, handle)。

懒加载路由在初始加载时以及导航或 fetcher 调用的 loadingsubmitting 阶段被解析。您不能懒加载定义路由匹配的属性(path, index, children),因为我们只在匹配到已知路由后才执行您的懒加载路由函数。

您的 lazy 函数通常会返回动态导入的结果。

// In this example, we assume most folks land on the homepage so we include that
// in our critical-path bundle, but then we lazily load modules for /a and /b so
// they don't load until the user navigates to those routes
let routes = createRoutesFromElements(
  <Route path="/" element={<Layout />}>
    <Route index element={<Home />} />
    <Route path="a" lazy={() => import("./a")} />
    <Route path="b" lazy={() => import("./b")} />
  </Route>,
);

然后在您的懒加载路由模块中,导出您想为该路由定义的属性。

export async function loader({ request }) {
  let data = await fetchData(request);
  return json(data);
}

// Export a `Component` directly instead of needing to create a React Element from it
export function Component() {
  let data = useLoaderData();

  return (
    <>
      <h1>You made it!</h1>
      <p>{data}</p>
    </>
  );
}

// Export an `ErrorBoundary` directly instead of needing to create a React Element from it
export function ErrorBoundary() {
  let error = useRouteError();
  return isRouteErrorResponse(error) ? (
    <h1>
      {error.status} {error.statusText}
    </h1>
  ) : (
    <h1>{error.message || error}</h1>
  );
}

此功能的一个实际例子可以在仓库的 examples/lazy-loading-router-provider 目录中找到。更多信息,请查看 lazy 文档

🙌 非常感谢 @rossipedia 的初步提议POC 实现

次要更新

  • 添加对 route.Component/route.ErrorBoundary 属性的支持 (#10045)
  • 添加对 route.lazy 的支持 (#10045)

补丁更新

  • 改进上下文提供程序的记忆化,以避免不必要的重新渲染 (#9983)
  • 修复 generatePath 在某些情况下错误应用参数的问题 (#10078)
  • [react-router-dom-v5-compat] 添加遗漏的数据路由器 API 重导出 (#10171)

完整更新日志v6.8.2...v6.9.0

v6.8.2

日期:2023-02-27

补丁更新

  • 如果 <Link to> 中的同源绝对 URL 超出了路由器 basename 的范围,则将其视为外部链接 (#10135)
  • 对于超出路由器 basename 范围的同源绝对 URL,正确执行硬重定向 (#10076)
  • 修复绝对 <Link to> URL 的 SSR 问题 (#10112)
  • StaticRouterProvider 的序列化水合数据中正确转义 HTML 字符 (#10068)
  • 修复 useBlocker 在 SSR 期间返回 IDLE_BLOCKER 的问题 (#10046)
  • createStaticHandlerquery() 方法中,确保为 defer loader 响应保留状态码和头信息 (#10077)
  • invariant 更改为 UNSAFE_invariant 导出,因为它仅供内部使用 (#10066)

完整更新日志v6.8.1...v6.8.2

v6.8.1

日期:2023-02-06

补丁更新

  • 移除对 POP 导航不准确的控制台警告并更新活动阻塞器逻辑 (#10030)
  • 仅对绝对 URL 重定向检查不同的源 (#10033)
  • 改进了 Link 组件中的绝对 URL 检测(现在也支持 mailto: URL)(#9994)
  • 修复部分对象(仅搜索或哈希)路径名丢失当前路径值的问题 (#10029)

完整更新日志v6.8.0...v6.8.1

v6.8.0

日期:2023-01-26

次要更新

支持在 <Link to> 中使用绝对 URL。如果 URL 是当前源,它仍会进行客户端导航。如果 URL 是不同的源,它将为新源发起一个新的文档请求。(#9900)

<Link to="https://neworigin.com/some/path">    {/* Document request */}
<Link to="//neworigin.com/some/path">          {/* Document request */}
<Link to="https://www.currentorigin.com/path"> {/* Client-side navigation */}

补丁更新

  • 修复了重新验证 fetcher 的 shouldRevalidate 调用的 2 个独立问题 (#9948)
    • shouldRevalidate 函数仅在*显式*重新验证场景中被调用(例如在 mutation 之后、手动调用 useRevalidator 或在 Remix 中用于设置 cookie 的 X-Remix-Revalidate 头)。它没有在也适用于导航 loader 重新验证的*隐式*重新验证场景中被正确调用,例如搜索参数的更改或点击当前页面的链接。现在它在这些额外场景中也能被正确调用。
    • 传递的参数不正确且彼此不一致,因为 current*/next* 参数反映了静态的 fetcher.load URL(因此是相同的)。相反,它们应该反映触发重新验证的导航(就像 form* 参数那样)。这些参数现在能正确反映触发的导航。
  • 修复通过 useSearchParams 移除搜索参数的 bug (#9969)
  • <fetcher.Form> 上遵守 preventScrollReset (#9963)
  • 修复哈希路由器在手动 URL 更改时的导航问题 (#9980)
  • <ScrollRestoration> 使用 pagehide 而不是 beforeunload。这有更好的跨浏览器支持,特别是在移动版 Safari 上。(#9945)
  • 不要在仅哈希更改的 mutation 提交上短路 (#9944)
  • isRouteErrorResponse 中移除 instanceof 检查,以避免服务器上的打包问题 (#9930)
  • 检测 defer 调用仅包含关键数据时,移除 AbortController (#9965)
  • 在对 File 类型的 FormData 条目进行 URL 编码时,将名称作为值发送 (#9867)
  • react-router-dom-v5-compat - 修复使用 CompatRouter 时 SSR useLayoutEffectconsole.error (#9820)

完整更新日志v6.7.0...v6.8.0

v6.7.0

日期:2023-01-18

次要更新

  • 添加 unstable_useBlocker/unstable_usePrompt 钩子,用于在应用程序的 location 源内阻塞导航 (#9709, #9932)
  • <Form> 添加 preventScrollReset 属性 (#9886)

补丁更新

  • useBeforeUnload 添加了透传的事件监听器选项参数 (#9709)
  • 修复存在可选参数时 generatePath 的问题 (#9764)
  • 更新 <Await> 以接受 ReactNode 作为子函数返回结果 (#9896)
  • 改进了 action/loader 中绝对重定向 URL 的检测 (#9829)
  • 修复了使用内存历史记录创建 URL 的问题 (#9814)
  • 修复了提交重定向时的滚动重置问题 (#9886)
  • 修复同源绝对重定向的 404 错误 (#9913)
  • 在测试中简化 jsdom 错误绕过方案 (#9824)

完整更新日志v6.6.2...v6.7.0

v6.6.2

日期:2023-01-09

补丁更新

  • 确保 SSR 期间 useId 的一致性 (#9805)

完整更新日志v6.6.1...v6.6.2

v6.6.1

日期:2022-12-23

补丁更新

  • 在 action 重定向时,将提交信息包含在 shouldRevalidate 中 (#9777, #9782)
  • 当 action 重定向到当前位置时,重置 actionData (#9772)

完整更新日志v6.6.0...v6.6.1

v6.6.0

日期:2022-12-21

更新内容

这个次要版本主要是为了稳定我们的数据路由器 SSR API,因为我们已经将新的 RouterProvider 连接到了 Remix 中,这是 React Router-ing Remix 工作的一部分。

次要更新

  • 移除 createStaticHandler/createStaticRouter/StaticRouterProviderunstable_ 前缀 (#9738)
  • 添加 useBeforeUnload() 钩子 (#9664)

补丁更新

  • 支持大写的 <Form method>useSubmit 的 method 值 (#9664)
  • 修复 <button formmethod> 表单提交的覆盖问题 (#9664)
  • 修复提交时显式的 replace 和提交到新路径时的 PUSH (#9734)
  • 阻止在 errorElement 中使用 useLoaderData (#9735)
  • StaticRouterProvider 中正确水合 Error 对象 (#9664)
  • 对于带有 hydrationData 的 SSR 应用,跳过初始滚动恢复 (#9664)
  • 修复了一些错误情况下 loader/action 数据未被正确清除的 bug (#9735)

完整更新日志v6.5.0...v6.6.0

v6.5.0

日期:2022-12-16

更新内容

此版本引入了对可选路由段的支持。现在,在任何路径段的末尾添加一个 ? 将使整个段变为可选的。这对静态段和动态参数都有效。

可选参数示例

  • <Route path=":lang?/about"> 将匹配
    • /:lang/about
    • /about
  • <Route path="/multistep/:widget1?/widget2?/widget3?"> 将匹配
    • /multistep
    • /multistep/:widget1
    • /multistep/:widget1/:widget2
    • /multistep/:widget1/:widget2/:widget3

可选静态段示例

  • <Route path="/home?"> 将匹配
    • /
    • /home
  • <Route path="/fr?/about"> 将匹配
    • /about
    • /fr/about

次要更新

  • 允许可选路由和可选静态段 (#9650)

补丁更新

  • 停止对部分命名参数进行不正确的匹配,例如 <Route path="prefix-:param">,以与 splat 参数的工作方式保持一致。如果您之前依赖此行为,建议在 useParams 调用处提取路径的静态部分:(#9506)
// Old behavior at URL /prefix-123
<Route path="prefix-:id" element={<Comp /> }>

function Comp() {
  let params = useParams(); // { id: '123' }
  let id = params.id; // "123"
  ...
}

// New behavior at URL /prefix-123
<Route path=":id" element={<Comp /> }>

function Comp() {
  let params = useParams(); // { id: 'prefix-123' }
  let id = params.id.replace(/^prefix-/, ''); // "123"
  ...
}
  • 在 SSR 文档 action 请求后,在 loader request 上保留 headers (#9721)
  • 修复发送到重新验证 loader 的请求,使其反映为 GET 请求 (#9660)
  • 修复深度嵌套可选段的问题 (#9727)
  • GET 表单现在在加载导航上暴露一个 submission (#9695)
  • 修复了多个错误冒泡到同一边界时的错误边界跟踪问题 (#9702)

完整更新日志v6.4.5...v6.5.0

v6.4.5

日期:2022-12-07

补丁更新

  • 修复了发送到重新验证 loader 的请求,使其反映为 GET 请求 (#9680)
  • isResponse 替代 instanceof Response 检查 (#9690)
  • 修复了在 Cloudflare Pages 或其他非浏览器环境中创建 URL 的问题 (#9682, #9689)
  • 为静态处理程序的 query/queryRoute 添加 requestContext 支持 (#9696)
    • 请注意,不稳定的 API queryRoute(path, routeId) 已更改为 queryRoute(path, { routeId, requestContext })

完整更新日志v6.4.4...v6.4.5

v6.4.4

日期:2022-11-30

补丁更新

  • 如果 action/loader 函数返回 undefined,则抛出错误,因为重新验证需要知道 loader 是否已执行过。undefined 在 SSR 序列化以进行水合时也会导致问题。您应始终确保您的 loader/action 返回一个值,如果您不想返回任何内容,可以返回 null。(#9511)
  • 正确处理到外部域的重定向 (#9590, #9654)
  • 在 307/308 重定向上保留 HTTP 方法 (#9597)
  • 在静态数据路由器中支持 basename (#9591)
  • 增强了 ErrorResponse 的主体,以在内部 403/404/405 场景中包含更具描述性的文本
  • 修复 NavLink 和后代 <Routes> 中编码字符的问题 (#9589, #9647)
  • 在使用内置水合时,正确序列化/反序列化 ErrorResponse 实例 (#9593)
  • 在静态数据路由器中支持 basename (#9591)
  • 依赖更新
    • @remix-run/router@1.0.4
    • react-router@6.4.4

完整更新日志v6.4.3...v6.4.4

v6.4.3

日期:2022-11-01

补丁更新

  • 在使用 createHashRouter 时生成正确的 <a href> 值 (#9409)
  • 更好地处理 URL 和路由路径中特殊字符的编码/匹配问题 (#9477, #9496)
  • 当一个 index 路由同时也有一个 path 时,生成正确的 formAction 路径名 (#9486)
  • 尊重 NavLink 上的 relative=path 属性 (#9453)
  • 修复 NavLink 对根 URL 的行为 (#9497)
  • 当传递 locationArg 时,useRoutes 应该能够返回 null (#9485)
  • 修复 createMemoryRouter 中的 initialEntries 类型 (#9498)
  • loader/action 重定向中支持 basename 和相对路由 (#9447)
  • 在寻找合适的提交 action 函数时,忽略无路径的布局路由 (#9455)
  • @remix-run/router 添加 UMD 构建 (#9446)
  • 修复在 Firefox 中本地文件执行时的 createURL (#9464)

完整更新日志v6.4.2...v6.4.3

v6.4.2

日期:2022-10-06

补丁更新

  • useFormAction 中尊重 basename (#9352)
  • 修复 IndexRouteObjectNonIndexRouteObject 类型,使 hasErrorElement 成为可选 (#9394)
  • 增强了无效使用数据路由器钩子时的控制台错误消息 (#9311)
  • 如果一个索引路由有子路由,将导致运行时错误。我们加强了 RouteObject/RouteProps 类型,以便在 TypeScript 中显示此错误。(#9366)

完整更新日志v6.4.1...v6.4.2

v6.4.1

日期:2022-09-22

补丁更新

  • 保留来自 initialEntries 的状态 (#9288)
  • 为 fetcher 到索引路由的 get 提交保留 ?index (#9312)

完整更新日志v6.4.0...v6.4.1

v6.4.0

日期:2022-09-13

更新内容

Remix 数据 API

哇,这是一个大更新!6.4.0 将 Remix 的所有数据加载和变更 API 都引入了进来。这里有一个简单的高层概述,但建议您去查看文档,特别是功能概述教程

新的 react-router API

  • 使用 createMemoryRouter 创建您的路由器
  • 使用 <RouterProvider> 渲染您的路由器
  • 使用路由 loader 加载数据,使用路由 action 进行变更
  • 使用路由 errorElement 处理错误
  • 使用 deferAwait 延迟非关键数据的加载

新的 react-router-dom API

  • 使用 createBrowserRouter/createHashRouter 创建您的路由器
  • 使用新的 <Form> 组件提交数据
  • 使用 useFetcher() 执行页面内数据加载和变更
  • 使用 deferAwait 延迟非关键数据的加载
  • 使用 <ScrollRestoration> 管理滚动位置
  • 使用 <Link relative="path"> 执行路径相对导航 (#9160)

补丁更新

  • 路径解析现在与尾部斜杠无关 (#8861)
  • <Routes location> 组件内,useLocation 返回作用域内的 location (#9094)
  • 如果定义了 <Link replace> 属性,则尊重它 (#8779)

完整更新日志v6.3.0...v6.4.0

v6.3.0

日期:2022-03-31

次要更新

  • 添加了 v5 到 v6 的向后兼容包 💜 (#8752)。官方指南可以在此讨论中找到。

完整更新日志v6.2.2...v6.3.0

v6.2.2

日期:2022-02-28

补丁更新

  • 修复了以特殊 URL 安全字符开头的嵌套 splat 路由 (#8563)
  • 修复了在某些情况下索引路由缺少路由上下文的 bug (#8497)

完整更新日志v6.2.1...v6.2.2

v6.2.1

日期:2021-12-17

补丁更新

  • 此版本将内部的 history 依赖更新到 5.2.0

完整更新日志v6.2.0...v6.2.1

v6.2.0

日期:2021-12-17

次要更新

  • 我们现在使用可静态分析的 CJS 导出。这使得在 Node ESM 脚本中可以使用命名导入(查看提交)。

补丁更新

  • 修复了 RoutePropselement 类型,它应该是一个 ReactNode (#8473)
  • 修复了顶层路由的 useOutlet bug (#8483)

完整更新日志v6.1.1...v6.2.0

v6.1.1

日期:2021-12-11

补丁更新

  • 在 v6.1.0 中,我们无意中发布了一个新的、未记录的 API,这可能会引入错误 (#7586)。我们已将 HistoryRouter 标记为 unstable_HistoryRouter,因为这个 API 在新的主版本发布前可能需要更改。

完整更新日志v6.1.0...v6.1.1

v6.1.0

日期:2021-12-10

次要更新

  • <Outlet> 现在可以接收一个 context 属性。这个值会传递给子路由,并可以通过新的 useOutletContext 钩子访问。详情请见API 文档。(#8461)
  • <NavLink> 现在可以接收一个子函数来访问其 props。(#8164)
  • 改进了 useMatchmatchPath 的 TypeScript 签名。例如,当你调用 useMatch("foo/:bar/:baz") 时,路径会被解析,返回类型将是 PathMatch<"bar" | "baz">。(#8030)

补丁更新

  • 修复了一个导致嵌套路由上 base64 编码 ID 支持中断的 bug (#8291)
  • 一些错误消息的改进 (#8202)

完整更新日志v6.0.2...v6.1.0

v6.0.2

日期:2021-11-09

补丁更新

  • <Link> 添加了 reloadDocument 属性。这允许 <Link> 像普通锚标签一样,在导航后重新加载文档,同时保持相对的 to 解析 (#8283)

完整更新日志v6.0.1...v6.0.2

v6.0.1

日期:2021-11-05

补丁更新

  • 添加一个默认的 <StaticRouter location> 值 (#8243)
  • 为在 <Routes> 内使用 <Route> 添加了不变性检查,以帮助人们进行更改 (#8238)

完整更新日志v6.0.0...v6.0.1

v6.0.0

日期:2021-11-03

React Router v6 来啦!

请阅读我们的博文,了解更多关于 v6 中所有精彩内容的信息,包括关于如何从 React Router v5 和 Reach Router 升级的说明

文档和示例 CC 4.0
编辑