【Next.js/daisy UI】子コンポーネント内で状態管理して、送信でまとめて親に渡そう

# はじめに
[前回の記事](https://qiita.com/ichi_react/items/568a0805276c3628ae2c)に続いて、
モーダル関連の記事になります。

# 問題
モーダル内にはデータベースへとデータを送付するための、処理を実装していました。
ですが、inputタグの`value`と`onChange`の値を親のonClick処理で送付するってことにハマりました。

# 解決方法
まずは、下記のコードです。
```typescript:ModalAddFolder.tsx
"use client";
import React, { useState } from "react";

import { Button } from "@/app/components/common/Button";
import { ModalBase } from "@/app/components/common/ModalBase/ModalBase";

interface ModalAddFolderProps {
  // データ通信が完成したらこっちを使う
  /**
   * onSubmit: (name: string) => Promise<void>;
   */
  onClickAddFolder: (name: string) => void;
  onClose: () => void;
}
export const ModalAddFolder: React.FC<ModalAddFolderProps> = ({ onClose, onClickAddFolder }) => {
  const [name, setName] = useState("");

  const onClickAdd = () => {
    onClickAddFolder(name);
  };

  return (
    <ModalBase title="フォルダを追加" description="フォルダを追加してください">
      <div className="flex items-center gap-2">
        <input
          type="text"
          placeholder="フォルダ名"
          className="input input-bordered w-full"
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
      </div>
      <div className="flex items-center gap-2">
        <Button text="キャンセル" className="btn-ghost" onClickButton={onClose} />
        <Button text="追加" className="btn-primary" onClickButton={onClickAdd} />
      </div>
    </ModalBase>
  );
};

```
下記のコードのように、まずはinputでstate管理したいところを保持します
```typescript
  const [name, setName] = useState("");
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   <input
        type="text"
        placeholder="フォルダ名"
        className="input input-bordered w-full"
        value={name}
        onChange={(e) => setName(e.target.value)}
    />
```
次に、propsで受け取る予定の`onClickAddFolder`を使い、
すでにクリックしたときに発火される関数を用意しておきます。
```typescript
  const onClickAdd = () => {
    onClickAddFolder(name);
  };
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    <Button text="追加" className="btn-primary" onClickButton={onClickAdd} />
```
親元では下記のように呼び出します。
```typescript:sidebar.tsx
"use client";
import React from "react";
import { useParams, usePathname } from "next/navigation";

import { CirclePlus } from "lucide-react";

import { LinkList } from "@/app/components/layout/Link";

import { FaRegUser } from "react-icons/fa";
import { Button } from "@/app/components/common/Button";
import { useModal } from "@/app/lib/hooks/useModal";

interface SidebarProps {
  userName: string;
  contents: { text: string; id: string }[];
}

export const Sidebar = ({ userName, contents }: SidebarProps) => {
  const pathname = usePathname();
  const { userId } = useParams();
  const { openModal, closeModal, ModalRenderer } = useModal();

  // 追加する処理をここに書く
  const handleAddFolder = (name: string) => {
    console.log(name);
    closeModal();
  };

  const onClickAddFolderModalOpen = () => {
    openModal("addFolder", { onClickAddFolder: handleAddFolder });
  };

  const customContents = contents.map((content) => ({
    ...content,
    id: `${userId}/${content.id}/`,
  }));

  const pathSegments = pathname.split("/");
  const activeId = `${pathSegments[2]}/${pathSegments[3]}/`;

  return (
    <>
      <aside className="flex flex-col gap-4 min-h-[100vh] pb-6 bg-base-200">
        <div className="flex flex-col items-start gap-8 h-full">
          <div className="flex items-center gap-2 p-4 border-b border-base-300 w-full">
            <FaRegUser className="text-xl" />
            <a className="text-xl font-semibold" href={`/dashboard/${userId}`}>
              {userName}
            </a>
          </div>
          <div className="border-b border-base-300 pb-[32px] w-full">
            <h2 className="px-4 text-sm font-medium text-base-content/60 uppercase tracking-wider mb-2">フォルダ</h2>
            <LinkList contents={customContents} activeId={activeId} />
          </div>
        </div>
        <div className="p-4 border-t border-base-300">
          <Button
            text="新しいフォルダを作成"
            icon={<CirclePlus className="h-4 w-4 mr-2" />}
            onClickButton={onClickAddFolderModalOpen}
          />
        </div>
      </aside>
      <ModalRenderer />
    </>
  );
};

```
呼び出すための関数をこのように用意します。
処理内容はよしなに。
```typescript
  // 追加する処理をここに書く
  const handleAddFolder = (name: string) => {
    console.log(name);
    closeModal();
  };
```
下記のように、handleAddFolderをpropsで渡します。
```typescript
  const onClickAddFolderModalOpen = () => {
    openModal("addFolder", { onClickAddFolder: handleAddFolder });
  };
```

これにより、コールバックでボタンを押下した時の処理が走るってことですね。
わかりやすく書くと、
- Modalのコンポーネントは、inputの値を管理する
- 呼び出し元のコンポーネントやもっと高レイヤーのコンポーネントで操作処理を記載する

やっていることはこれですね。

# おわりに
前回の記事にも書きましたが、
途中にuseModalというカスタムフックがあったため、
このような形になりました。