今年早些时候,我们开始着手 Remix React 路由,旨在将所有 Remix 数据 API(loaders
、actions
、fetchers
等)迁移到 React Router。随着最近发布的 React Router v6.4.0,我们很自豪地宣布我们已经完成了这项工作......并且我们认为我们做得更好 😃。我们不仅修复了一些边缘情况的错误,还稳定了一些 API 并引入了一些非常棒的新 API。以下是更改的快速概述,但我们鼓励您查看博客文章以获取更多信息。
useRevalidator
以编程方式重新验证defer
/Await
将您的关键/非关键数据分离useRouteLoaderData
获取特定路由的加载器数据unstable_shouldReload
已稳定为 shouldRevalidate
<ScrollRestoration getKey>
方法允许更精细地控制滚动恢复errorElement
fetcher.load
调用现在参与重新验证 - 正如他们应该一直以来的那样!现在我们可以反转脚本并开始 React 路由 Remix,以便我们可以将这些更改带回 Remix 用户(并在过程中删除 大量 Remix 代码)。对你们所有人的好消息是,我们计划以迭代方式进行,并且不会进行重大发布 🤯。我们认为我们正在使用的方法非常酷,所以我们想与大家分享。
您可以将 Remix 的架构视为具有 4 个主要方面
这 4 个部分也恰好是很好地解耦的,因此它们为我们提供了干净的边界,以迭代的方式来处理这个问题,以避免一次性的大爆炸发布。这应该意味着 Remix 用户将拥有更平滑的集成路径!
我们首先将更新 Remix 的服务器运行时以使用 React Router 的新 unstable_createStaticHandler
来执行服务器端数据获取,一旦我们感到满意,就可以发布它,而无需触及步骤 2 到 4。更棒的是 - 我们可以将其分解为资源路由请求、客户端导航数据获取请求和文档请求的单独工作。
注意:createStaticHandler
在 6.4.0
中被发布为不稳定的,以防我们在此过程中遇到所需的更改。一旦我们完成了 Remix 集成,我们将使其稳定。
我们计划使用 Martin Fowler 的 绞杀者无花果 模式逐个进行,这样我们就可以获得最大的信心,确保我们没有引入任何回归(向 @DavidKPiano
致敬,因为他在几个月前 重新将此模式呈现在我的脑海中!)。如果您不熟悉此模式,它的基本原理是,您在旧代码旁边编写新代码,然后慢慢地将部分代码切换过来。我们可以通过使用功能标志方法进一步推进此方法,该方法使两条路径都保持活动状态,并允许在测试和运行时进行验证。
以下是在 Remix 中,资源路由请求可能看起来像的简化示例
function handleResourceRouteRequest({ request }) {
// If the flag is enabled, clone the request so we can use it twice
let response = processResourceRouteRequest(
ENABLE_NEW_STUFF ? request.clone() : request,
);
// When our flag is enabled, send this request through the new
// code path, while also asserting that we get back an identical
// response
if (ENABLE_NEW_STUFF) {
let newResponse = processResourceRouteRequestNew(request);
assertResponses(response, newResponse);
return newResponse;
}
return response;
}
这种方法为我们提供了许多好处
dev
分支中,而不是维护一个长期存在的特性分支。一旦我们完成了服务器端数据获取,就可以继续进行服务器端 HTML 渲染(使用 React Router 的 unstable_StaticRouterProvider
)。这也是我们可以(某种程度上)独立进行的另一个方面。我们可以使用新的 API 在服务器上渲染 HTML,但如果我们没有一些糟糕的代码分支来确定是从旧上下文还是新上下文读取,我们将无法在客户端(使用旧 API)对其进行水合。值得庆幸的是,惯用的 Remix 应用程序无需 JavaScript 即可工作,因此我们可以在此步骤中无需 JS 即可验证我们的测试和应用程序。显然,我们不会在步骤 2 之后发布,但我们能够在我们继续进行步骤 3 之前,对我们的 SSR 获得相当高的信心。同样,我们将使用一个标志来启用两条路径,并在旧路径和新路径之间执行一定程度的 HTML 断言。
这里有趣的部分是,此步骤是我们开始完全实现 Michael 的愿景的地方,即 Remix 是一个 "React 路由的编译器"。现在 react-router 知道如何执行所有酷炫的数据获取操作,Remix 只需将一组传统的磁盘上的路由文件编译成 React Router 所期望的适当路由。一旦创建了这些路由,它就会将其交给 React Router 进行繁重的工作 💪!
继续进行客户端水合!在这里,我们将删除绝大多数 Remix 代码(再见,过渡管理器 - 我们将永远爱你 🙃)。与上面相同,Remix 只需利用服务器提供的路由清单来生成路由树,然后将其交给 createBrowserRouter
,然后 RouterProvider
完成其余的工作。超级酷的部分是 Remix 能够使用完全相同的加载器和操作来执行其所有路由,因为它们只做一件事,即使用 _data
参数对 Remix 服务器进行 fetch
!这可能不会经过功能标志,因为我们不能完全对文档进行两次水合 🤷♂️。
这可能是软件开发中最不准确的断言短语,但我们将在这里固执己见,再次使用它 - 一旦我们完成步骤 3,客户端路由和数据获取应该 正常工作™️,因为现在完全由 React Router 6.4 处理!
我们再次指出,我们计划将所有这些都作为 Remix 1.x 的次要版本发布(步骤 1 可能发布一个版本,步骤 2-4 发布另一个版本)。为了保持向后兼容性,在步骤 2 和 3 中需要做一些工作。以下是一些示例
useTransition
在 React Router 6.4 中已重命名为 useNavigation
,因此我们将标记 useTransition
为已弃用,但仍保留它。submission
字段并从导航(以前称为过渡)和获取器中删除了 type
字段,因此我们将使用包装器钩子将它们添加回 useTransition
和 useFetcher
。在可能的情况下(我们希望这涵盖所有情况),我们将在 remix.config.js
中添加功能标志,允许您根据自己的方便选择加入新的 Remix v2 行为,同时在您不选择加入的情况下提供向后兼容的行为。
我们对下一步感到非常兴奋,对它为 React Router 和 Remix 的未来带来的可能性(有人说 Preact 吗?)感到更加兴奋。请留意存储库以获取更新,一如既往,如果您有任何疑问或对所有这一切有任何兴奋之处,请随时在 Discord 或 Twitter 上联系我们 :)