React Router v7 已發布。 查看文件
漸進式增強

漸進式增強

漸進式增強是網頁設計中的一種策略,它首先強調網頁內容,允許每個人訪問網頁的基本內容和功能,同時具有額外瀏覽器功能或更快網際網路存取的用戶則會收到增強的版本。

- 維基百科

由 Steven Champeon 和 Nick Finck 在 2003 年提出,這個詞組出現在當時不同瀏覽器之間 CSS 和 JavaScript 支援度差異很大的時期,當時許多用戶實際上是在禁用 JavaScript 的情況下瀏覽網頁。

今天,我們很幸運能夠為一個更加一致的網路進行開發,而且大多數用戶都啟用了 JavaScript。

但是,我們仍然相信 Remix 中漸進式增強的核心原則。它可以實現快速、彈性強且開發工作流程簡單的應用程式。

效能:雖然很容易認為只有 5% 的用戶網路連線速度較慢,但現實情況是 100% 的用戶在 5% 的時間裡網路連線速度較慢。

彈性:在 JavaScript 加載完成之前,每個人的 JavaScript 都是禁用的。

簡潔性:使用 Remix 以漸進式增強的方式建構應用程式,實際上比建構傳統的 SPA 更簡單。

效能

從伺服器傳送 HTML 允許應用程式比典型的單頁應用程式 (SPA) 平行執行更多操作,從而加快初始加載體驗和後續的導覽速度。

典型的 SPA 會傳送空白的文件,並且僅在 JavaScript 加載完成後才開始工作。

HTML        |---|
JavaScript      |---------|
Data                      |---------------|
                            page rendered 👆

Remix 應用程式可以在請求到達伺服器的瞬間開始工作,並串流傳輸響應,以便瀏覽器可以開始平行下載 JavaScript、其他資產和數據。

               👇 first byte
HTML        |---|-----------|
JavaScript      |---------|
Data        |---------------|
              page rendered 👆

彈性和可存取性

雖然您的用戶可能不會禁用 JavaScript 瀏覽網頁,但每個人的 JavaScript 在完成加載之前都是禁用的。一旦您開始伺服器呈現 UI,您就需要考慮在 JavaScript 加載完成之前他們嘗試與應用程式互動時會發生什麼。

Remix 透過在其 HTML 之上建立抽象來擁抱漸進式增強。這表示您可以建構一個無需 JavaScript 即可運作的應用程式,然後在上面添加 JavaScript 以增強體驗。

最簡單的案例是 <Link to="/account">。這些會呈現一個 <a href="/account"> 標籤,該標籤無需 JavaScript 即可運作。當 JavaScript 加載時,Remix 將攔截點擊並使用客戶端路由處理導覽。這樣您就可以更好地控制 UX,而不僅僅是在瀏覽器選項卡中旋轉網站圖示,但無論哪種方式都可以運作。

現在考慮一個簡單的加入購物車按鈕。

export function AddToCart({ id }) {
  return (
    <Form method="post" action="/add-to-cart">
      <input type="hidden" name="id" value={id} />
      <button type="submit">Add To Cart</button>
    </Form>
  );
}

無論 JavaScript 是否已加載都沒關係,此按鈕都會將產品新增至購物車。

當 JavaScript 加載時,Remix 將攔截表單提交並在客戶端進行處理。這允許您新增自己的待定 UI 或其他客戶端行為。

簡潔性

當您開始依賴基本網路功能(如 HTML 和 URL)時,您會發現您使用客戶端狀態和狀態管理的情況會少得多。

考慮一下之前的按鈕,在不對程式碼進行任何基本更改的情況下,我們可以加入一些客戶端行為

import { useFetcher } from "@remix-run/react";

export function AddToCart({ id }) {
  const fetcher = useFetcher();

  return (
    <fetcher.Form method="post" action="/add-to-cart">
      <input name="id" value={id} />
      <button type="submit">
        {fetcher.state === "submitting"
          ? "Adding..."
          : "Add To Cart"}
      </button>
    </fetcher.Form>
  );
}

當 JavaScript 正在載入時,此功能與之前一樣繼續運作,但一旦 JavaScript 載入

  • useFetcher 不再像 <Form> 一樣導致導覽,因此使用者可以停留在同一頁面並繼續購物。
  • 應用程式碼決定待處理的 UI,而不是在瀏覽器中旋轉網站圖示。

這不是關於以兩種不同的方式建立它——一次針對 JavaScript,一次不針對 JavaScript——而是關於以迭代的方式建立它。從最簡單的版本開始開發並發佈;然後迭代到增強的使用者體驗。

使用者不僅會獲得漸進式增強的體驗,應用程式開發人員也可以在不改變功能基本設計的情況下「漸進式增強」UI。

另一個漸進式增強帶來簡潔性的例子是 URL。當您從 URL 開始時,您不必擔心客戶端狀態管理。您可以直接使用 URL 作為 UI 的事實來源。

export function SearchBox() {
  return (
    <Form method="get" action="/search">
      <input type="search" name="query" />
      <SearchIcon />
    </Form>
  );
}

此元件不需要任何狀態管理。它只會呈現一個提交到 /search 的表單。當 JavaScript 加載時,Remix 將攔截表單提交並在客戶端處理它。這允許您添加自己的待處理 UI 或其他客戶端行為。這是下一個迭代。

import { useNavigation } from "@remix-run/react";

export function SearchBox() {
  const navigation = useNavigation();
  const isSearching =
    navigation.location.pathname === "/search";

  return (
    <Form method="get" action="/search">
      <input type="search" name="query" />
      {isSearching ? <Spinner /> : <SearchIcon />}
    </Form>
  );
}

架構上沒有根本性的改變,只是對使用者和程式碼進行了漸進式增強。

另請參閱:狀態管理

文件和範例授權於 MIT