実現したいこと
ユーザーがフォーム等に値を入力後、
・ページをリロードしようとした時に確認ダイアログを表示する。
・他のページに遷移しようとした時に確認ダイアログを表示する。
課題
react-router-dom v6ではページ離脱を防ぐために必要なuseBlockerが削除されていて、別途実装が必要。
使用したライブラリ
react-router-prompt
https://github.com/sshyam-gupta/react-router-prompt/tree/main
実際は、このライブラリの中で必要な3つのファイルのみをコピーして使いました。
https://github.com/sshyam-gupta/react-router-prompt/blob/main/src/hooks/use-confirm.ts
https://github.com/sshyam-gupta/react-router-prompt/blob/main/src/hooks/use-prompt.ts
https://github.com/sshyam-gupta/react-router-prompt/blob/main/src/index.tsx
理由としては、react-routerの非公式のライブラリで今後も継続的にアップデートされるかが分からなかったのと、上記3つのファイルのみ移植するだけで使えそうだったので、今回はライブラリをそのまま使うのではなく、コードを移植して使いました。
こちらが自作したコードのリポジトリです。
https://github.com/nobu0605/react-router-prompt
もちろん、ライブラリをそのまま使うことも可能です。
使い方
ライブラリを使った場合も自作の場合も同じで以下のようにReactRouterPromptを呼び出して、ダイアログなどをラップして使っています。
when propsに変更検知のflagを渡します。
import ReactRouterPrompt from "./ReactRouterPrompt";
import Button from "@mui/material/Button";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
type Props = {
when: boolean;
};
export function UnsavedConfirmDialog({ when }: Props) {
return (
<ReactRouterPrompt when={when}>
{({ isActive, onConfirm, onCancel }) =>
isActive && (
<Dialog open={isActive}>
<DialogTitle>Do you really want to leave?</DialogTitle>
<DialogContent>
<DialogContentText>
Your changes will not be saved.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={onCancel}>cancell</Button>
<Button onClick={onConfirm} autoFocus>
ok
</Button>
</DialogActions>
</Dialog>
)
}
</ReactRouterPrompt>
);
}
補足
ページをリロードしようとした時に確認ダイアログを表示する場合に、beforeunloadイベントを使うのですが、カスタムメッセージや自作のダイアログは表示できないみたいです。
各ブラウザの既定のダイアログが表示されます。
https://qiita.com/nantekkotai/items/9a6e2c98ed704934ab47