今年稍早,我們開始著手將 React Router 與 Remix 整合,目標是將所有 Remix Data API(loaders
、actions
、fetchers
等)移至 React Router。隨著最近 React Router v6.4.0 的發布,我們很自豪地宣布,我們已完成這項工作...而且我們認為我們讓它們變得更好了😃。我們不僅修復了一些邊緣案例的錯誤,還穩定了一些 API 並引入了一些非常棒的新 API。以下是變更的快速概述,但我們鼓勵您查看部落格文章以獲取更多資訊。
useRevalidator
程式化地重新驗證defer
/Await
分隔您的重要/非重要資料useRouteLoaderData
取得特定路由的 loader 資料unstable_shouldReload
已穩定為 shouldRevalidate
<ScrollRestoration getKey>
方法可對捲動還原進行更精細的控制errorElement
fetcher.load
呼叫現在參與重新驗證 - 就像它們一直應該做的那樣!現在,我們要反過來,開始 **React Router 與 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)上對其進行 hydration,而無需一些糟糕的程式碼分支來確定是從舊的還是新的上下文讀取。值得慶幸的是,慣用的 Remix 應用程式可以在沒有 JavaScript 的情況下運作,因此我們可以在此步驟中驗證我們的測試和應用程式,而無需 JS。顯然我們不會在步驟 2 之後發布,但是我們將能夠在進入步驟 3 之前對我們的 SSR 獲得相當高的信心。我們將再次使用標誌來啟用這兩個路徑,並在舊的和新的之間執行某種程度的 HTML 斷言。
這裡有趣的部分是,此步驟是我們開始充分認識到 Michael 的願景,即 Remix 是一個 「React Router 的編譯器」。現在,react-router 知道如何執行所有酷炫的資料擷取工作,Remix 只會將磁碟上的一組慣例路由檔案編譯為 React Router 期望的適當路由。一旦建立了這些路由,它就會將它們交給 React Router 進行繁重的工作💪!
進入用戶端 hydration!這就是我們將刪除絕大部分 Remix 程式碼的地方(再見 Transition Manager - 我們會永遠愛你 🙃)。與上述類似,Remix 只需要利用伺服器提供的路由資訊清單來生成一個路由樹,以交給 createBrowserRouter
,然後 RouterProvider
完成其餘的工作。*超級*酷的部分是,Remix 可以為其所有路由使用*完全相同的 loader 和 action*,因為它們所做的只是使用 _data
參數向 Remix 伺服器發出 fetch
請求!這可能不會通過功能標誌,因為我們不能完全對文件進行兩次 hydration 🤷♂️。
這可能是軟體開發中最不正確的主張,但我們將在此處固執地再次使用它 - 一旦我們完成步驟 3,用戶端路由和資料擷取應該**Just Work™️**,因為現在這完全由 React Router 6.4 處理!
我們應該再次注意,我們計劃將所有這些作為次要的 Remix 1.x 版本發布(步驟 1 可能一個版本,步驟 2-4 另一個版本)。為了保持回溯相容性,在步驟 2 和 3 中需要完成一些工作。以下是一些範例
useTransition
在 React Router 6.4 中已重新命名為 useNavigation
,因此我們會將 useTransition
標記為已棄用,但會保留它submission
欄位扁平化,並從導航(以前的轉換)和擷取器中刪除了 type
欄位,因此我們將使用包裝器 hook 將這些欄位加回 useTransition
和 useFetcher
在可能的情況下(我們希望所有情況都是如此),我們將在 remix.config.js
中新增功能標誌,讓您可以根據自己的方便選擇加入新的 Remix v2 行為,同時在您不選擇加入的情況下提供回溯相容的行為。
我們對下一步感到非常興奮,並且對它為 React Router 和 Remix 的未來打開的一些可能性(有人說 Preact 嗎?)感到更加興奮。請密切關注 repo 以獲取更新,並且一如既往,如果您對任何或所有這些內容有任何疑問或興奮,請在 Discord 或 Twitter 上與我們聯繫:)