【Vite × React × TypeScript】Chakra UI v3でDrawerメニューからの遷移時、メニューが閉じない事象の解消方法

# はじめに

お疲れ様です。りつです。

今回はChakra UI v3でドロワーを実装中に意図しない挙動になったので、その解決記事です。

# 問題

現在、以下のようなヘッダーメニューを作成中です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3911933/9aefc1f7-7f87-3c1d-838f-0ee6c0783ea4.png)

画面右上のハンバーガーメニューのアイコンをクリックすると、以下の画像のようなドロワーメニューが表示されるのですが、メニュー（例えば「TOP」の部分）をクリックしてもドロワーメニューが閉じませんでした。
(遷移先のURLに遷移自体はしています)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3911933/621f5ec9-01d2-0a83-0f21-f6252e3cb85c.png)

## ソースコード

```react:src/components/organisms/layout/Hader.tsx
import React, { memo, useCallback, useState } from "react";
import { useNavigate } from "react-router";
import { Box, Flex, Heading, Link } from "@chakra-ui/react";
import { MenuDrawer } from "@/components/molecules/MenuDrawer";

export const Header: React.FC = memo(() => {
  const [ open, setOpen ] = useState(false);
  const navigate = useNavigate ();

  const onClickHome = useCallback(() => navigate('/home'), []);
  const onClickUserManagement = useCallback(() => navigate('/home/user_management'), []);
  const onClickSetting = useCallback(() => navigate('/home/setting'), []);

  return (
    <>
      <Flex
        as="nav"
        bg="teal.500"
        color="gray.50"
        align="center"
        justify="space-between"
        padding={{ base: 3, md: 5 }}
      >
        <Flex align="center" as="a" mr={8} _hover={{ cursor: "pointer" }} onClick={onClickHome}>
        <Heading as="h1" fontSize={{ base: "md", md: "lg" }}>
          ユーザー管理アプリ
        </Heading>
        </Flex>
        <Flex align="center" fontSize="sm" flexGrow={2} display={{ base: "none", md: "flex" }}>
          <Box pr={4}>
            <Link color="gray.50" onClick={onClickUserManagement}>ユーザー一覧</Link>
          </Box>
            <Link color="gray.50" onClick={onClickSetting}>設定</Link>
        </Flex>
        <MenuDrawer
          open={open}
          setOpen={setOpen}
          onClickHome={onClickHome}
          onClickUserManagement={onClickUserManagement}
          onClickSetting={onClickSetting}
        />
      </Flex>
    </>
  );
});
```

```react:src/components/molecules/MenuDrawer.tsx
import React, { memo } from "react";
import { Button } from "@chakra-ui/react";
import {
  DrawerBackdrop,
  DrawerBody,
  DrawerContent,
  DrawerRoot,
  DrawerTrigger,
} from "@/components/ui/drawer"
import { MenuIconButton } from "@/components/atoms/button/MenuIconButton";

type Props = {
  open: boolean;
  setOpen: React.Dispatch<React.SetStateAction<boolean>>;
  onClickHome: () => void;
  onClickUserManagement: () => void;
  onClickSetting: () => void;
}

export const MenuDrawer: React.FC<Props> = memo((props) => {
  const { open, setOpen, onClickHome, onClickUserManagement, onClickSetting } = props;
  return (
    <DrawerRoot placement="start" size="xs" open={open} onOpenChange={(e) => setOpen(e.open)}>
      <DrawerBackdrop />
      <DrawerTrigger asChild>
        <MenuIconButton/>
      </DrawerTrigger>
      <DrawerContent>
        <DrawerBody p={0} bg="gray.100">
          <Button w="100%" bg="gray.100" color="gray.800" onClick={onClickHome}>TOP</Button>
          <Button w="100%" bg="gray.100" color="gray.800" onClick={onClickUserManagement}>ユーザー一覧</Button>
          <Button w="100%" bg="gray.100" color="gray.800" onClick={onClickSetting}>設定</Button>
        </DrawerBody>
      </DrawerContent>
    </DrawerRoot>
  );
});
```

```react:src/components/atoms/button/MenuIconButton.tsx
import React, { memo } from "react";
import { IconButton } from "@chakra-ui/react";
import { RxHamburgerMenu } from "react-icons/rx";

export const MenuIconButton: React.FC = memo(React.forwardRef<HTMLButtonElement>((props, ref) => {
  return (
    <IconButton
      ref={ref}
      {...props}
      aria-label="メニューボタン"
      size="sm"
      bg="teal.500"
      display={{ base: "block", md: "none"}}
    >
      <RxHamburgerMenu />
    </IconButton>
  );
}));
```

# 解決方法

ページ遷移用のボタンを`<DrawerActionTrigger>`で囲むことで解消できました。

```diff_jsx:src/components/molecules/MenuDrawer.tsx
import React, { memo } from "react";
- import { Button } from "@chakra-ui/react";
+ import { Button, DrawerActionTrigger } from "@chakra-ui/react";
import {
  DrawerBackdrop,
  DrawerBody,
  DrawerContent,
  DrawerRoot,
  DrawerTrigger,
} from "@/components/ui/drawer"
import { MenuIconButton } from "@/components/atoms/button/MenuIconButton";

type Props = {
  open: boolean;
  setOpen: React.Dispatch<React.SetStateAction<boolean>>;
  onClickHome: () => void;
  onClickUserManagement: () => void;
  onClickSetting: () => void;
}

export const MenuDrawer: React.FC<Props> = memo((props) => {
  const { open, setOpen, onClickHome, onClickUserManagement, onClickSetting } = props;
  return (
    <DrawerRoot placement="start" size="xs" open={open} onOpenChange={(e) => setOpen(e.open)}>
      <DrawerBackdrop />
      <DrawerTrigger asChild>
        <MenuIconButton/>
      </DrawerTrigger>
      <DrawerContent>
        <DrawerBody p={0} bg="gray.100">
-         <Button w="100%" bg="gray.100" color="gray.800" onClick={onClickHome}>TOP</Button>
+         <DrawerActionTrigger asChild> {/* ボタンをDrawerActionTriggerで囲む */}
+           <Button w="100%" bg="gray.100" color="gray.800" onClick={onClickHome}>TOP</Button>
+         </DrawerActionTrigger>
-         <Button w="100%" bg="gray.100" color="gray.800" onClick={onClickUserManagement}>ユーザー一覧</Button>
+         <DrawerActionTrigger asChild> {/* ボタンをDrawerActionTriggerで囲む */}
+           <Button w="100%" bg="gray.100" color="gray.800" onClick={onClickUserManagement}>ユーザー一覧</Button>
+         </DrawerActionTrigger>
-         <Button w="100%" bg="gray.100" color="gray.800" onClick={onClickSetting}>設定</Button>
+         <DrawerActionTrigger asChild> {/* ボタンをDrawerActionTriggerで囲む */}
+           <Button w="100%" bg="gray.100" color="gray.800" onClick={onClickSetting}>設定</Button>
+         </DrawerActionTrigger>
        </DrawerBody>
      </DrawerContent>
    </DrawerRoot>
  );
});
```

# おわりに

解決方法としてはシンプルでした。

今後もChakra UI v3については調べつつ実装していきたいと思います。

# 参考

https://www.chakra-ui.com/docs/components/drawer