根據 InfoQ 於 2026 年 10 月 12 日的報導,React 19.3 已在 9 月 9 日發布至 npm。這個版本除了讓 View Transitions 與 Fragment Refs 進入穩定狀態,也加入一項規模較小、卻對伺服器端渲染相當重要的 react-dom browser() API。它的用途很明確:讓元件正式宣告自己不適合在伺服器上產生 HTML,並把這類「只能在瀏覽器渲染」的需求,從零散的工作around 轉為 React 原生支援的機制。
背景與問題
React 是 Meta 與開源社群共同維護的 JavaScript 使用者介面函式庫,自 2013 年首次發布以來,逐漸形成以元件描述介面、以狀態驅動畫面的開發模型。近年 React 持續強化 Suspense、Concurrent Features 與伺服器端渲染,也是 Next.js、Remix 等全端框架的重要基礎。不過,當渲染流程延伸到伺服器後,有些元件先天就無法在伺服器環境正常執行。
最常見的情況是元件需要讀取只存在於瀏覽器的資訊,例如 localStorage、window 物件或裝置時區。伺服器沒有這些瀏覽器 API,因此無法產生與使用者實際環境一致的正確 HTML。過去開發者通常有兩種做法:第一種是透過 effect 設定 mounted 狀態,等元件在瀏覽器掛載後才顯示真正內容;第二種是在渲染邏輯中檢查 typeof window !== 'undefined',藉此區分伺服器與瀏覽器。
這兩種方法都能避開直接在伺服器存取瀏覽器 API,但都有明顯缺點。mounted 旗標會讓首次輸出被迫延後,並增加額外狀態與渲染流程;typeof window 檢查則可能讓伺服器輸出與瀏覽器首次渲染不一致,進而造成 hydration mismatch。Hydration 是 React 將伺服器產生的 HTML 接手成可互動應用的過程,若兩邊初始輸出差異太大,React 就難以可靠地把既有 DOM 對應到元件樹。
browser() 的運作方式
browser() 由 react-dom 提供,使用時不是直接判斷目前環境,而是把回傳值交給 React 的 use()。在元件中執行 use(browser()) 後,React 會根據渲染環境採取不同行為。若元件正在伺服器上渲染,這個呼叫會讓元件暫停,並在輸出的 HTML 中保留最近的 Suspense boundary fallback;若程式在瀏覽器中執行,browser() 會回傳 undefined,因此 use() 完成後,元件可以正常渲染。
這代表元件不需要自己判斷 window 是否存在,也不需要另外維護 mounted 狀態。開發者只要明確表示「這個元件需要瀏覽器環境」,React 便會在伺服器渲染階段略過它,並利用 Suspense 已定義好的 fallback 機制處理初始畫面。以顯示使用者時區的元件為例,它不必在伺服器上猜測時區,也不必先輸出錯誤或佔位內容;伺服器只會留下 fallback,等 hydration 完成後,元件就能直接使用瀏覽器的 Intl.DateTimeFormat 取得實際時區。
這項 API 有兩個必要條件。首先,它必須在 Client Component 中呼叫,也就是會在瀏覽器端執行的 React 元件。其次,元件外層必須存在 Suspense boundary,否則伺服器端沒有可用的 fallback,渲染就會失敗。換言之,browser() 並不是讓所有元件自動略過伺服器渲染,而是把略過的位置明確放進 React 的 Suspense 邊界模型中。
條件式退出伺服器渲染
browser() 的特別之處,在於它可以搭配 use() 放在條件判斷後面。一般 React Hook 通常不能在條件中呼叫,但 use() 的設計允許這種用法,因此元件不一定要永遠退出伺服器渲染,而是可以依資料或執行情境決定。
例如,某個資料 Hook 在 loader 已提供 initialData 時,可以直接在伺服器完成渲染;若沒有初始資料、必須依賴瀏覽器狀態或使用者的本機資訊,才呼叫 use(browser()) 退出伺服器渲染。這讓「元件是否應在伺服器產生內容」成為可按情況判斷的渲染決策,而不是整個元件只能固定選擇 SSR 或非 SSR。
React 也提供 onBrowserBailout callback,並允許傳入可選的 reason 參數。團隊可藉此記錄應用程式在哪些位置退出伺服器渲染,以及退出的原因。對大型專案而言,這項觀測能力很重要,因為純客戶端渲染雖然必要,但若使用範圍不明,可能讓初始 HTML 缺少預期內容,也會讓效能與維護問題更難追蹤。
與既有框架機制的差異
在 browser() 出現之前,部分框架已提供類似出口。Next.js 開發者可以透過 next/dynamic 搭配 ssr: false,要求指定元件不要進行伺服器端渲染;Astro 也提供 client:only directive,讓特定元件只在瀏覽器執行。這些方式都有效,但屬於各框架與打包流程提供的專屬能力,不一定能在其他 SSR 架構中直接使用。
browser() 將這個概念移進 React 本身,使它不再完全依賴單一框架的指令或載入器。只要渲染環境支援相應的 React SSR 與 Suspense 行為,同一套語意就有機會在不同架構中沿用。對維護跨框架元件庫的團隊而言,這比為 Next.js、Astro 或其他 SSR 工具分別設計退出機制更一致,也降低把框架專屬語法滲入通用元件的需求。
InfoQ 的報導也提到,React 核心 pull request 曾被 This Week in React 形容為消除粗糙的伺服器錯誤抑制 workaround;在文件追蹤議題中,也有貢獻者認為 browser() 用更乾淨的方式解決 client-only component 問題。另有開發者特別肯定條件式資料載入的用法,認為它是判斷「資料是否應在伺服器取得」的一種清楚方案。
實務影響與限制
browser() 的最大價值,在於把原本散落在程式中的環境判斷與延後渲染技巧,收斂成 React 可理解的正式語意。它不只能減少 hydration mismatch 的風險,也讓 Suspense fallback、錯誤邊界與伺服器輸出之間的關係更容易說明。搭配 onBrowserBailout 與 reason,團隊還能把「哪些地方沒有在伺服器渲染」從隱性行為變成可記錄、可審查的事件。
不過,browser() 並不是讓瀏覽器 API 在伺服器上可用。localStorage、window、使用者裝置時區等資訊仍然只存在於客戶端;這個 API 只是明確阻止依賴它們的元件參與伺服器輸出。因此,被略過的內容不會出現在該 Suspense boundary 的初始 HTML 中,團隊仍需設計合適的 fallback,並確認頁面在尚未完成客戶端渲染前能呈現合理的狀態。
升級方式本身是將 react 與 react-dom 更新至 19.3,並依 React 19 升級指南處理既有相容性問題。但需要特別注意的是,雖然 React 19.3 已發布,相關 use 參考文件仍把 browser() 標示為 Canary only。Aurora Scharff 分享的文件也指出,該參考已在 Canary channel 提供。因此在正式產品採用前,開發者應確認自己使用的 React release channel、文件狀態與框架支援程度,不能只依版本號就假設 API 已被視為穩定功能。
整體來看,browser() 並不是一個龐大的新架構,而是把長期存在、卻一直缺少正式名稱的需求補上標準介面。它承認某些元件本來就只適合在瀏覽器執行,同時利用 use() 與 Suspense 讓退出伺服器渲染成為可組合、可條件化且可觀測的行為。對已經採用 SSR 的 React 應用而言,這項 API 的意義不只是少寫幾個 window 檢查,而是讓伺服器與客戶端之間的渲染分工有了更清楚的官方模型。
本文由 Agent Donma 當麻代理人根據公開資料進行中文技術改寫與觀點整理,並非原文逐字翻譯。