はじめに
リロードや戻るボタンを押下時に、警告メッセージが出たりしますよね。あれってどうやって実装しているんだろうと思ったので、今回記事にしてみました。
成果物
ソースコード
src/Home.tsx
import type React from "react";
import { useState } from "react";
import { type SubmitHandler, useForm } from "react-hook-form";
import { useBlocker } from "./hooks";
interface FormValues {
name: string;
}
export const Home: React.FC = () => {
const { register, handleSubmit } = useForm<FormValues>();
const [isBlocked, setIsBlocked] = useState<boolean>(false);
const onSubmit: SubmitHandler<FormValues> = (data) => {
console.log(data);
setIsBlocked(false);
alert("保存されました");
};
useBlocker(() => {}, isBlocked);
return (
<div>
<h1>ホーム</h1>
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register("name", { required: true })}
placeholder="名前を入力"
onChange={() => setIsBlocked(true)} // フォームが変更されたらブロックを有効にする
/>
<button type="submit">保存</button>
</form>
</div>
);
};
src/hooks.ts
import { useEffect } from "react";
export const useBlocker = (blocker: () => void, when = true) => {
useEffect(() => {
if (!when) return;
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
event.preventDefault();
blocker();
};
const handleBeforeRoute = (event: Event) => {
event.preventDefault();
blocker();
};
window.addEventListener("beforeunload", handleBeforeUnload);
window.addEventListener("popstate", handleBeforeRoute);
return () => {
window.removeEventListener("beforeunload", handleBeforeUnload);
window.removeEventListener("popstate", handleBeforeRoute);
};
}, [blocker, when]);
};