漸進式增強
本頁面內容

漸進式增強

漸進式增強是網頁設計中的一種策略,其重點在於首先呈現網頁內容,讓所有人都能存取網頁的基本內容和功能,同時讓擁有額外瀏覽器功能或更快網際網路連線速度的使用者獲得增強的版本。

- 維基百科

當搭配伺服器端渲染 (框架模式中的預設設定) 使用 React Router 時,您可以自動利用漸進式增強的優點。

為何漸進式增強至關重要

這個詞彙由 Steven Champeon 和 Nick Finck 於 2003 年提出,在當時各種瀏覽器對 CSS 和 JavaScript 的支援度不一,而且許多使用者實際上是在 JavaScript 停用的情況下瀏覽網頁的。

如今,我們很幸運能在一個更一致的網頁環境中開發,而且大多數使用者都已啟用 JavaScript。

然而,我們仍然相信 React Router 中漸進式增強的核心原則。它能帶來快速、彈性佳的應用程式,並簡化開發工作流程。

效能:雖然很容易認為只有 5% 的使用者連線速度緩慢,但現實情況是 100% 的使用者有 5% 的時間連線速度緩慢。

彈性:在 JavaScript 載入完成之前,所有人都是在 JavaScript 停用的情況下使用網頁。

簡潔性:以漸進式增強的方式搭配 React Router 建置應用程式,實際上比建置傳統的 SPA 更簡單。

效能

伺服器渲染讓您的應用程式能比典型的單頁應用程式 (SPA) 更平行地執行更多工作,從而加快初始載入體驗和後續導航速度。

典型的 SPA 會傳送空白文件,而且只在 JavaScript 載入完成後才開始工作

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

React Router 應用程式可以在請求到達伺服器的那一刻開始工作,並串流回應,讓瀏覽器可以開始平行下載 JavaScript、其他資產和資料

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

彈性與可及性

雖然您的使用者可能不會在 JavaScript 停用的情況下瀏覽網頁,但在 JavaScript 完成載入之前,所有人都是在沒有 JavaScript 的情況下使用網站。React Router 透過在 HTML 之上建置來擁抱漸進式增強,讓您能以無需 JavaScript 也能運作的方式建置應用程式,然後疊加 JavaScript 以增強體驗。

最簡單的例子是 <Link to="/account">。這些會渲染 <a href="/account"> 標籤,即使沒有 JavaScript 也能運作。當 JavaScript 載入時,React Router 會攔截點擊並使用用戶端路由處理導航。這讓您能更掌控 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 載入時,React Router 會攔截表單提交並在用戶端處理。這讓您可以新增您自己的待處理 UI 或其他用戶端行為。

簡潔性

當您開始依賴網頁的基本功能 (例如 HTML 和 URL) 時,您會發現您對用戶端狀態和狀態管理的需求會大幅減少。

考慮先前的按鈕,在程式碼沒有任何根本變更的情況下,我們可以加入一些用戶端行為

import { useFetcher } from "react-router";

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 載入時,React Router 會攔截表單提交並在用戶端處理。以下是下一個迭代版本

import { useNavigation } from "react-router";

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>
  );
}

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

另請參閱:狀態管理

文件與範例 CC 4.0