😊

【NextJs14】NextJs14 と 便利なライブラリ【#13Usehooks-ts 】

2023/12/27に公開

【#13Usehooks-ts 】

YouTube: https://youtu.be/AjAAdnDfL4A

https://youtu.be/AjAAdnDfL4A

今回はusehooks-tsの便利な機能を見ていきます。

https://usehooks-ts.com/

まずは、「isMounted」の部分を「useIsClient」を使って
書き換えていきます。

components/providers/modals-provider.tsx
"use client";

import { useEffect, useState } from "react";
import { useUser } from "@clerk/nextjs";
import { useIsClient } from "usehooks-ts";
import { UserProfileModal } from "../modals/user-profile-modal";

export const ModalsProvider = () => {
  const [isMounted, setIsMounted] = useState(false);
  const isClient = useIsClient();
  const { user } = useUser();

  // useEffect(() => {
  //   setIsMounted(true);
  // }, []);

  // if (!isMounted) {
  //   return null;
  // }

  if (!isClient) {
    return null;
  }

  return (
    <>
      <UserProfileModal email={user?.emailAddresses[0].emailAddress || ""} />
    </>
  );
};

次に「useEventListener」を使って
キーボード入力でモーダルが開くようにします。

app/(main)/_components/main-sidebar.tsx
"use client";

import { Copy, Database, Home, Image, ShieldCheck, User } from "lucide-react";
import { Separator } from "@/components/ui/separator";
import { MainSidebarItem } from "./main-sidebar-item";
import { Button } from "@/components/ui/button";
import { useModal } from "@/store/use-modal-store";
import { useEffect } from "react";
import { useEventListener } from "usehooks-ts";

export type MenuItem = {
  id: string;
  href: string;
  pathname: string;
  label: string;
  icon: React.ReactNode;
};

const menuItems = [
  {
    id: "0",
    href: "/home",
    pathname: "/home",
    label: "Home",
    icon: <Home className="h-5 w-5 mr-3 group-hover:text-white" />,
  },
  {
    id: "1",
    href: "/account",
    pathname: "/account",
    label: "Account",
    icon: <User className="h-5 w-5 mr-3 group-hover:text-white" />,
  },
  {
    id: "2",
    href: "/images",
    pathname: "/images",
    label: "Images",
    icon: <Image className="h-5 w-5 mr-3 group-hover:text-white" />,
  },
  {
    id: "3",
    href: "/data",
    pathname: "/data",
    label: "Data",
    icon: <Database className="h-5 w-5 mr-3 group-hover:text-white" />,
  },
  {
    id: "4",
    href: "/protected",
    pathname: "/protected",
    label: "Protected",
    icon: <ShieldCheck className="h-5 w-5 mr-3 group-hover:text-white" />,
  },
];

export const MainSidebar = () => {
  const { onOpen } = useModal();

  const modalOpen = (e: KeyboardEvent) => {
    if (e.key === "c" && (e.metaKey || e.ctrlKey)) {
      e.preventDefault();
      onOpen();
    }
  };

  // useEffect(() => {
  //   window.addEventListener("keydown", modalOpen);

  //   return () => {
  //     window.removeEventListener("keydown", modalOpen);
  //   };
  // }, []);

  useEventListener("keydown", modalOpen);

  return (
    <div className="w-full flex py-4 px-4 flex-col items-center">
      <div className="w-full">
        <h3 className="text-lg">Menu</h3>
      </div>
      <Separator className="bg-slate-400 mt-2" />
      <div className="w-full py-4">
        <ul>
          {menuItems.map((item) => (
            <MainSidebarItem key={item.id} item={item} />
          ))}
        </ul>
      </div>
      <Separator className="bg-slate-400 mt-2" />
      <div className="w-full py-4">
        <Button
          onClick={onOpen}
          className="w-full flex items-center gap-x-2"
          variant="primary"
        >
          <Copy className="h-4 w-4" />
          Copy Email
        </Button>
      </div>
    </div>
  );
};

Discussion