はじめに
Chakra UIのDrawerを使ってハンバーガーメニューをコンポーネント化しようとした際に、少しハマったので解決方法を共有します。
問題
Chakra UIのDrawerを使ってハンバーガーメニューをコンポーネント化しようとしましたが、うまくいきませんでした。
解決方法
ハンバーガーメニューの部分だけを子コンポーネントに移動しても解決しませんでした。propsやuseStateなどを試しましたが、うまく動作しませんでした。
解決策は、"DrawerTrigger asChild" コンポーネントを含めて子コンポーネントに移動することでした。
うまくいかなかったコード
Header.jsx
import { memo, useState } from 'react';
import { Flex, Heading, Link, Box, IconButton, Button } from '@chakra-ui/react';
import { MenuIconButton } from "@/components/atoms/button/MenuIconButton.tsx";
import {
DrawerActionTrigger,
DrawerBackdrop,
DrawerBody,
DrawerCloseTrigger,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerRoot,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer"
// 中略
export const Header: React.FC = memo(() => {
return (
<>
<DrawerRoot placement={"start"} open={open} onOpenChange={(e) => setOpen(e.open)}>
<DrawerBackdrop />
<DrawerTrigger asChild>
<MenuIconButton />
</DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle>Drawer Title</DrawerTitle>
</DrawerHeader>
<DrawerBody p={0} bg="gray.100">
<Button w="100%" variant="outline">Top</Button>
<Button w="100%" variant="outline">ユーザー一覧</Button>
<Button w="100%" variant="outline">設定</Button>
</DrawerBody>
<DrawerCloseTrigger />
</DrawerContent>
</DrawerRoot>
</>
)
});
MenuIconButton.jsx
import { memo } from 'react';
import { Flex, Heading, Link, Box, IconButton, Button } from '@chakra-ui/react';
import { FaBars } from "react-icons/fa6";
// 中略
export const MenuIconButton: React.FC = (() => {
return (
<>
<IconButton
align="right"
aria-label="メニューボタン"
size="sm"
variant="unstyled"
colorPalette={"teal"}
display={{ base: "block", md: "none" }}
>
<FaBars />
</IconButton>
</>
)
});
うまくいったコード
Header.jsx
import { memo, useState } from 'react';
import { Flex, Heading, Link, Box, IconButton, Button } from '@chakra-ui/react';
import { MenuIconButton } from "@/components/atoms/button/MenuIconButton.tsx";
import {
DrawerActionTrigger,
DrawerBackdrop,
DrawerBody,
DrawerCloseTrigger,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerRoot,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer"
// 中略
export const Header: React.FC = memo(() => {
const [open, setOpen] = useState(false) //追加
return (
<>
{/* open,onOpenChangeのpropsを追加 */}
<DrawerRoot placement={"start"} open={open} onOpenChange={(e) => setOpen(e.open)}>
<DrawerBackdrop />
{/* MenuIconButton.jsxに移動 <DrawerTrigger asChild> */}
<MenuIconButton />
{/* 同じく移動 </DrawerTrigger> */}
<DrawerContent>
<DrawerHeader>
<DrawerTitle>Drawer Title</DrawerTitle>
</DrawerHeader>
<DrawerBody p={0} bg="gray.100">
<Button w="100%" variant="outline">Top</Button>
<Button w="100%" variant="outline">ユーザー一覧</Button>
<Button w="100%" variant="outline">設定</Button>
</DrawerBody>
<DrawerCloseTrigger />
</DrawerContent>
</DrawerRoot>
</>
)
});
MenuIconButton.jsx
import { memo } from 'react';
import { Flex, Heading, Link, Box, IconButton, Button } from '@chakra-ui/react';
import { FaBars } from "react-icons/fa6";
import {
DrawerTrigger,
} from "@/components/ui/drawer" // Headerコンポーネントから移動
// 中略
export const MenuIconButton: React.FC = (() => {
return (
<>
{/* Headerコンポーネントから移動 */}
<DrawerTrigger asChild>
<IconButton
align="right"
aria-label="メニューボタン"
size="sm"
variant="unstyled"
colorPalette={"teal"}
display={{ base: "block", md: "none" }}
>
<FaBars />
</IconButton>
{/* Headerコンポーネントから移動 */}
</DrawerTrigger>
</>
)
});
おわりに
細かい部分はドキュメントに記載されていないことも多いので、経験を積んで勘を磨いていきます。
参考