2022 第7週 實作筆記:在離開路由前顯示確認視窗
總結
本篇筆記記錄如何使用 react-router-dom (v5) 的 useHistory()
與 Web API beforeunload
event 在以下時間點跳出確認訊息:
- 使用者點擊重新整理(
beforeunload
) - 使用者關閉分頁(
beforeunload
) - 使用者按下「上(下)一頁」準備離開當下畫面(
history.block()
)
原始碼:https://github.com/tzynwang/react-router-block/tree/version/2
版本
react-router-dom: 5.3.0
webpack: 5.69.0
筆記
useBlock
-
beforeunload
能偵測的是「重新整理」與「關閉分頁」這兩種行為,而使用者點擊「上(下)一頁」會由useHistory()
產生的history
instance 來阻擋 -
從 args 傳入
block
參數,讓 useBlock 可以在特定條件下解除阻擋行為(例:使用者已經填完表單所有內容) -
第 25-31 行:當引用 useBlock 的元件掛載至畫面上時,將
history.block()
回傳的 instance 保存到變數BLOCK
中,並在引用 useBlock 的元件從畫面上卸載時,執行BLOCK
-
第 26 行:使用
window.confirm
彈出瀏覽器原生的對話框,詢問使用者是否離開網頁,選擇不離開(!leave
)則回傳false
取消離開的行為 -
參考
@types/history
可得知history.block()
與其 args 的 type 分別如下列:export interface History<HistoryLocationState = LocationState> { block( prompt?: boolean | string | TransitionPromptHook<HistoryLocationState> ): UnregisterCallback; } export type TransitionPromptHook<S = LocationState> = ( location: Location<S>, action: Action ) => string | false | void;
為了讓 type check 不會報錯,在使用者確認離開畫面時,讓傳入
history.block()
的匿名函式回傳undefined
而非true
(第 30 行)
無條件阻擋:About 元件
直接在元件中呼叫 useBlock()
,並傳入空物件(不需解除條件)
有條件阻擋:Form 元件
傳入 useState
變數 block
,在使用者按下送出表單的按鈕時,將 block
設定為 false
,並在畫面重新整理(元件重新掛載到畫面上後),重設 block
為 true
避免 F5 後阻擋失效
webpack devServer 設定
- 在後端 server 沒有配合的情況下,使用
BrowserRouter
來處理路由會導致畫面重新整理、或是使用者直接輸入路由時遭遇 404 - 如果在開發時使用 webpack devServer 來執行 react APP,則設定
webpack.config.js
的devServer
其historyApiFallback: true
即可使用BrowserRouter
devServer: { historyApiFallback: true; }
- 若 react APP 是部署到 GitHub Pages(或任何無法配合 history mode 的 server)則需使用
react-router-dom
的HashRouter
來處理路由,而路由會帶上井字號