【React】props多すぎ問題を解決したい

# はじめに
個人で作ったプロジェクトのコンポーネント分割を行っていたところ、propsを10個以上定義する必要がありました。
コンポーネント分割したもののpropsが多く、解決方法はないか調べたことをまとめてみました。

# 問題
コンポーネント分割した際にpropsが多くなる

```tsx:App.tsx
  return (
    <>
          <Search
            getData={getData}
            additivesSearch={additivesSearch}
            isDetailedFilterOpen={isDetailedFilterOpen}
            setIsDetailedFilterOpen={setIsDetailedFilterOpen}
            handleSubmit={handleSubmit}
            register={register}
            setValue={setValue}
            resetField={resetField}
            onAdditivesSubmit={onAdditivesSubmit}
            handleReset={() => handleReset(true)}
          />
    </>
  );
}
```

# 解決方法
### 1.オブジェクトにまとめ、スプレッド構文`{...オブジェクト名}`を使って設定する
```tsx:App.tsx
const searchProps = {
  getData: getData,
  additivesSearch: additivesSearch,
  isDetailedFilterOpen: isDetailedFilterOpen,
  setIsDetailedFilterOpen: setIsDetailedFilterOpen,
  handleSubmit: handleSubmit,
  register: register,
  setValue: setValue,
  resetField: resetField,
  onAdditivesSubmit: onAdditivesSubmit,
  handleReset: () => handleReset(true)
};

// 省略

  return (
    <>
      <Search {...searchProps} />
    </>
  );
}
```

**MDNより引用**
>スプレッド (...) 構文を使うと、配列式や文字列などの反復可能オブジェクトを、0 個以上の引数（関数呼び出しの場合）や要素（配列リテラルの場合）を目的の場所に展開することができます。

スプレッド構文で、オブジェクト内のプロパティを一つずつ展開できると理解しました。

### 2.Custom Hooksを使う
1の方法は`<Search {...searchProps} />`で指定することで、すっきりしましたが、propsの指定が多いことには変わりがありません。

App.tsxに定義していたSearchコンポーネント関連するものをuseSearchFormとして`CustomHooks化`しました。
⇒Searchコンポーネント内に定義することと同じかと思いましたが、再利用できるため、カスタムフック化してみました。

```ts:useSearchForm.ts
import { useForm, type SubmitHandler } from "react-hook-form";
import type { AdditivesSearch } from "../domain/AdditivesSearch";

export const useSearchForm = (
  additivesSearch: (formData: AdditivesSearch) => Promise<void>
) => {
  const { handleSubmit, register, setValue, resetField } =
    useForm<AdditivesSearch>();

  const onAdditivesSubmit: SubmitHandler<AdditivesSearch> = (formData) => {
    if (formData.have_additives === "0") {
      formData.additives = "";
      formData.additivesWord = "";
    }
    additivesSearch(formData);
  };

  const handleReset = (have_additives_rest: boolean) => {
    resetField("sake_name");
    if (have_additives_rest) {
      setValue("have_additives", "");
    }
    resetField("additives");
    resetField("additivesWord");
    resetField("maker");
  };

  return {
    handleSubmit,
    register,
    setValue,
    resetField,
    onAdditivesSubmit,
    handleReset,
  };
};

```

```tsx:App.tsx
import { useSearchForm } from "./hooks/useSearchForm.ts";

const searchForm = useSearchForm(additivesSearch);

const searchProps = {
    getData,
    additivesSearch,
    isDetailedFilterOpen,
    setIsDetailedFilterOpen,
    ...searchForm,
    handleReset: () => handleReset(true),
};

// 省略

  return (
    <>
      <Search {...searchProps} />
    </>
  );
}
```

# おわりに
スプレッド構文は配列のコピー、要素の追加で使うものと思っていましたが、オブジェクトでも使用できることがわかりました。
コンポーネントの分割することで、役割分担できて見やすいと思う一方で、分割するのが難しいとも感じました。

# 参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax

https://ja.react.dev/learn/passing-props-to-a-component

https://ja.react.dev/reference/react/hooks