2022 第7週 實作筆記:在離開路由前顯示確認視窗

總結

本篇筆記記錄如何使用 react-router-dom (v5) 的 useHistory() 與 Web API beforeunload event 在以下時間點跳出確認訊息:

leave prompt

原始碼:https://github.com/tzynwang/react-router-block/tree/version/2

版本

react-router-dom: 5.3.0
webpack: 5.69.0

筆記

useBlock

import { useEffect } from 'react'
import { useHistory } from 'react-router-dom'
import { UnregisterCallback } from 'history'
interface useBlockArgs {
block?: boolean
}
let BLOCK: UnregisterCallback
export default function useBlock(args: useBlockArgs) {
const history = useHistory()
const { block } = args
const preventCloseAndRefresh = (event: BeforeUnloadEvent) => {
const e = event || window.event
e.preventDefault()
if (e) e.returnValue = ''
return ''
}
useEffect(() => {
if (block === false) return
window.addEventListener('beforeunload', preventCloseAndRefresh)
BLOCK = history.block(() => {
const leave = window.confirm('Leave this page?')
if (!leave) {
return false
}
return undefined
})
return () => {
window.removeEventListener('beforeunload', preventCloseAndRefresh)
BLOCK()
}
}, [block])
}
view raw useBlock.tsx hosted with ❤ by GitHub

無條件阻擋:About 元件

import React, { memo } from 'react'
import useBlock from '@Hooks/useBlock'
function AboutPage(): React.ReactElement {
useBlock({})
return <div>this is the about page.</div>
}
export default memo(AboutPage)
view raw block.About.tsx hosted with ❤ by GitHub

直接在元件中呼叫 useBlock(),並傳入空物件(不需解除條件)

有條件阻擋:Form 元件

import React, { memo, useState, useEffect } from 'react'
import useBlock from '@Hooks/useBlock'
function FormPage(): React.ReactElement {
const [block, setBlock] = useState<boolean>(true)
useBlock({ block })
useEffect(() => setBlock(true), [])
return (
<div>
<label htmlFor="fname">First name:</label>
<br />
<input type="text" id="fname" name="fname" value="John" required />
<br />
<label htmlFor="lname">Last name:</label>
<br />
<input type="text" id="lname" name="lname" value="Doe" required />
<br />
<br />
<button onClick={() => setBlock(false)}>submit</button>
<br />
Block status:{' '}
{block
? 'page is block, click the submit button to unblock'
: 'page is NOT block'}
</div>
)
}
export default memo(FormPage)
view raw block.Form.tsx hosted with ❤ by GitHub

傳入 useState 變數 block,在使用者按下送出表單的按鈕時,將 block 設定為 false,並在畫面重新整理(元件重新掛載到畫面上後),重設 blocktrue 避免 F5 後阻擋失效

webpack devServer 設定

參考文件