快速刷新 (Fast Refresh)
快速刷新 (Fast Refresh) 是 Next.js 整合的 React 功能,當您保存檔案變更時,可在維持客戶端暫存狀態的情況下即時重新載入瀏覽器頁面。此功能在 9.4 或更新版本 的所有 Next.js 應用程式中預設啟用。啟用快速刷新後,多數編輯內容應能在一秒內顯示。
運作原理
- 若您編輯的檔案 僅匯出 React 元件,快速刷新將僅更新該檔案的程式碼,並重新渲染您的元件。您可以編輯該檔案中的任何內容,包括樣式、渲染邏輯、事件處理程序或副作用 (effects)。
- 若您編輯的檔案包含 非 React 元件的匯出內容,快速刷新將重新執行該檔案及其導入該檔案的其他檔案。例如若
Button.js
和Modal.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.log
或debugger;
。 - 請記住導入是區分大小寫的。當您的導入與實際檔名不符時,快速和完整刷新都可能失敗。例如
'./header'
與'./Header'
。
快速刷新與 Hooks
在可能的情況下,快速刷新會嘗試保留元件狀態於編輯之間。特別是 useState
和 useRef
會保留其先前值,只要您不變更其參數或 Hook 呼叫順序。
具有依賴項的 Hooks——如 useEffect
、useMemo
和 useCallback
——在快速刷新期間將_始終_更新。其依賴項列表在快速刷新發生時會被忽略。
例如,當您將 useMemo(() => x * 2, [x])
編輯為 useMemo(() => x * 10, [x])
時,即使 x
(依賴項)未變更,它仍會重新執行。若 React 不這麼做,您的編輯將不會反映在畫面上!
有時這可能導致非預期結果。例如,即使 useEffect
的依賴項陣列為空,它在快速刷新期間仍會重新執行一次。
然而,撰寫能承受 useEffect
偶發重新執行的程式碼是良好實踐,即使沒有快速刷新也如此。這將使您未來更容易為其新增依賴項,且此做法受 React 嚴格模式 (React Strict Mode) 強制要求,我們強烈建議啟用該模式。