Skip to content

20260421tue

Published: at 15:00

20260421tue

ポイント

useCallBackは第二引数が変わると再生成される。

window.addEventLisner = ブラウザに、第一引数に対して、第二引数の反応をするようにセットする。

useEffect の仕様として、コールバックが関数を返すとそれがクリーンアップ関数になると決まっている。 useEffectでやったことを「元に戻す」処理を書く。 useEffect(()=>{ retrun ()=> },[] )

コードの流れ

posts/selectedIndex/router が変わる → useCallback が新しい handleKeyDown を生成 → useEffect が古いリスナーをremove → 新しいリスナーをadd

コード

// キー上下で記事を選択。エンターで記事編集ページに移動。
// 第二引数のいずれかが変更されると再生成される。
const handleKeyDown = useCallback(
  (e: KeyboardEvent) => {
    if (posts.length === 0) return;

    if (e.key === "ArrowDown") {
      e.preventDefault();
      setSelectedIndex(prev =>
        prev === null ? 0 : Math.min(prev + 1, posts.length - 1)
      );
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setSelectedIndex(prev =>
        prev === null ? posts.length - 1 : Math.max(prev - 1, 0)
      );
    } else if (e.key === "Enter" && selectedIndex !== null) {
      router.push(`/admin/posts/${posts[selectedIndex].id}/edit`);
    }
  },
  [posts, selectedIndex, router]
);

// handleKeyDownが再生成されるたびに動く。
useEffect(() => {
  // ブラウザにセットする。('keydown'が起きたら, handleKeyDownを設定する。
  window.addEventListener("keydown", handleKeyDown);
  // クリーンアップ関数。useEffectの処理をもとに戻す。
  return () => window.removeEventListener("keydown", handleKeyDown);
}, [handleKeyDown]);