💮
React HooksでWindowEventを扱う
hooksの定義
hooksでwindow eventを扱うためにカスタムhookを定義します。
import { DependencyList, useEffect } from "react";
const useWindowEvent = <K extends keyof WindowEventMap>(
type: K,
listener: (this: Window, ev: WindowEventMap[K]) => any,
deps: DependencyList,
options?: boolean | AddEventListenerOptions
) =>
useEffect(() => {
if (window) {
window.addEventListener(type, listener, options);
return () => {
window.removeEventListener(type, listener, options);
};
}
}, deps);
基本的にはwindow.addEventListenerの引数と同じ方を使っているので汎用性の高いhookが使用できます。
使い方
cmd, ctrl + s でコンテンツを保存する時に"keydown"イベントを監視して関数を実行するなどのケースで使用できます。
const Index: FC = () => {
...
const handleSave = useCallback(
(e: KeyboardEvent) => {
if ((e.ctrlKey || e.metaKey) && e.key === "s") {
if (!isSubmitting) {
onSubmit(title, body);
}
e.preventDefault();
return false;
}
},
[title, body, isSubmitting])
useWindowEvent("keydown", handleSave, [title, body, isSubmitting])
...
}
また上記を使用したカスタムhookを定義することもでき、
例としてbefore unloadイベント時にアラートを表示するカスタムhookを定義してみます。
export const useBeforeUnloadAlert = (
diff: boolean | (() => boolean),
deps: DependencyList
) => {
const handler = useCallback(
(e: BeforeUnloadEvent) => {
if (typeof diff === "boolean" ? diff : diff()) {
e.preventDefault();
e.returnValue = "";
}
},
[deps]
);
useWindowEvent("beforeunload", handler, deps);
};
上記を使用する事で以下のような形でhooksを利用する事ができました
const Index: FC = () => {
...
useBeforeUnloadAlert(()=>{
return props.title !== title;
},[props.title, title])
// or
useBeforeUnloadAlert(props.title !== title, [props.title, title])
...
}
Discussion