快速刷新 (Fast Refresh)

快速刷新 (Fast Refresh) 是 Next.js 整合的 React 功能,當您保存檔案變更時,可在維持客戶端暫存狀態的情況下即時重新載入瀏覽器頁面。此功能在 9.4 或更新版本 的所有 Next.js 應用程式中預設啟用。啟用快速刷新後,多數編輯內容應能在一秒內顯示。

運作原理

  • 若您編輯的檔案 僅匯出 React 元件,快速刷新將僅更新該檔案的程式碼,並重新渲染您的元件。您可以編輯該檔案中的任何內容,包括樣式、渲染邏輯、事件處理程序或副作用 (effects)。
  • 若您編輯的檔案包含 React 元件的匯出內容,快速刷新將重新執行該檔案及其導入該檔案的其他檔案。例如若 Button.jsModal.js 都導入 theme.js,編輯 theme.js 將會更新這兩個元件。
  • 最後,若您編輯的檔案被 React 樹之外的檔案導入,快速刷新 將退回執行完整重新載入。您可能有個檔案既渲染 React 元件,又匯出被 非 React 元件 導入的值。例如,您的元件可能同時匯出一個常數,而某個非 React 工具檔案導入了它。此時可考慮將該常數移至獨立檔案,並讓兩個檔案都導入它。這將讓快速刷新重新生效。其他情況通常也能用類似方式解決。

錯誤恢復能力

語法錯誤

若您在開發過程中造成語法錯誤,修正後再次儲存檔案即可。錯誤會自動消失,無需重新載入應用程式。元件狀態不會遺失

執行時錯誤

若您的錯誤導致元件內部發生執行時錯誤,將出現情境式錯誤覆蓋層。修正錯誤後,覆蓋層會自動消失,無需重新載入應用程式。

若錯誤未發生在渲染過程中,元件狀態將被保留。若錯誤發生於渲染期間,React 會使用更新後的程式碼重新掛載您的應用程式。

若您的應用中設有 錯誤邊界 (error boundaries)(這對生產環境的優雅降級是個好做法),它們會在渲染錯誤後的下次編輯時重試渲染。這表示使用錯誤邊界可避免您總是被重置回根應用狀態。但請注意,錯誤邊界不應_過度_細分。它們是 React 在生產環境中的機制,應始終有意識地設計。

限制

快速刷新會嘗試保留您編輯元件中的本地 React 狀態,但僅在安全情況下進行。以下是您可能看到每次編輯檔案時本地狀態被重置的原因:

  • 類別元件 (class components) 的本地狀態不會保留(僅函式元件和 Hooks 會保留狀態)。
  • 您編輯的檔案可能 除了 React 元件外還包含其他匯出內容。
  • 有時檔案會匯出高階元件 (HOC) 的呼叫結果,如 HOC(WrappedComponent)。若返回的元件是類別,其狀態將被重置。
  • 匿名箭頭函式如 export default () => <div />; 會導致快速刷新無法保留本地元件狀態。對於大型程式碼庫,您可使用我們的 name-default-component 代碼修改工具

隨著更多程式碼轉用函式元件和 Hooks,您可預期狀態在更多情況下被保留。

技巧

  • 快速刷新預設會保留函式元件(及 Hooks)中的 React 本地狀態。
  • 有時您可能想 強制 重置狀態並重新掛載元件。例如,這在調整僅在掛載時發生的動畫時很有用。為此,您可在編輯的檔案中任意位置加入 // @refresh reset。此指令僅作用於該檔案,會指示快速刷新在每次編輯時重新掛載該檔案中定義的元件。
  • 您可在開發期間於編輯的元件中加入 console.logdebugger;
  • 請記住導入是區分大小寫的。當您的導入與實際檔名不符時,快速和完整刷新都可能失敗。例如 './header''./Header'

快速刷新與 Hooks

在可能的情況下,快速刷新會嘗試保留元件狀態於編輯之間。特別是 useStateuseRef 會保留其先前值,只要您不變更其參數或 Hook 呼叫順序。

具有依賴項的 Hooks——如 useEffectuseMemouseCallback——在快速刷新期間將_始終_更新。其依賴項列表在快速刷新發生時會被忽略。

例如,當您將 useMemo(() => x * 2, [x]) 編輯為 useMemo(() => x * 10, [x]) 時,即使 x(依賴項)未變更,它仍會重新執行。若 React 不這麼做,您的編輯將不會反映在畫面上!

有時這可能導致非預期結果。例如,即使 useEffect 的依賴項陣列為空,它在快速刷新期間仍會重新執行一次。

然而,撰寫能承受 useEffect 偶發重新執行的程式碼是良好實踐,即使沒有快速刷新也如此。這將使您未來更容易為其新增依賴項,且此做法受 React 嚴格模式 (React Strict Mode) 強制要求,我們強烈建議啟用該模式。

On this page