beforeunload イベントのリスナでページ遷移を防ぐ処理は 最近だと任意テキストを表示できないし 個別にリスナを登録する意味は特に無い
モジュールごとにリスナを登録していくと 後から強制的に移動させたい場合に解除が面倒
なので ページ遷移を防ぐ処理だけをモジュールにまとめた

let listener_added = false
const set = new Set()

const listener = (event) => event.returnValue = "preventer"

export const prevent = (key) => {
set.add(key)
if (set.size && !listener_added) {
window.addEventListener("beforeunload", listener)
listener_added = true
}
}

export const unprevent = (key) => {
set.delete(key)
if (!set.size && listener_added) {
window.removeEventListener("beforeunload", listener)
listener_added = false
}
}

export const forceUnpreventAll = () => {
for (const key of set) {
unprevent(key)
}
}

export const getReasons = () => [...set]

prevent 関数の引数にキーを入れて呼び出す
キーは任意の型で文字列とかシンボルとか
1 つ以上登録されてればページ遷移しようとするとダイアログが出る

unprevent 関数の引数にキーを入れて呼び出すと 対応する prevent を解除する

forceUnpreventAll 関数を呼び出すと全部の prevent を解除する
ただし このモジュール外で登録した beforeunload があれば ダイアログは出る

getReasons 関数でキーのリストを取得できる
現状がページ遷移がブロックされる状態かの判断や 何が原因でブロックされる状態なのかを確認できる

現状の実装だと prevent に登録されたキー数が 0, 1 の切り替わりでリスナの付け外しをしてるけど 常に付けておいて returnValue に代入するかを切り替えるでもよかったかも