なつねこメモ

主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ

書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。

2022/10/31

React Hooks でフォームデータを送信したい

カテゴリー:TypeScriptReact

React Hooks でフォームデータ (multipart/form-data)を POST したいけど、いまいち参考例がなかったので、作ってみたというメモ。
といってもやり方は普通に useSWRuseFetch とかと同じ感じかな。

React Hooks 自体はこんな感じ

useForm.ts

import axios from "axios";
import { useCallback, useState } from "react";

type State<TResponse, TError> = {
  response: TResponse | null;
  error: TError | null;
  loading: boolean;
};

type Args = {
  url: string;
}

const useForm = <TRequest extends Record<string, unknown>, TResponse, TError = unknown>({
  url
}: Args) => {
  const [state, setState] = useState<State<TResponse, TError>>({
    response: null,
    error: null,
    loading: false
  });

  const submit = useCallback((payload: TRequest) => {
    setState({ ...state, loading: true });

    const form = new FormData();

    for (const key of Object.keys(payload)) {
      form.append(key, payload[key]);
    }

    axios.post(url, form, {
      headers: { "content-type": "multipart/form-data" }
    }).then((w) => {
      const response = w.data as TResponse;
      setState({ ...state, response, loading: false });
    }).catch((err) => {
      const error = err as TError;
      setState({ ...state, error, loading: false});
    });
  }, [url]);

  return { ...state, submit } as const;
}

export default useForm;

使う側的にはこんな感じかな:

Form.tsx

import React from "react";

type Props = {};

const SomeForm: React.FC<Props> = () => {
  const { response, error, loading, submit } = useForm({ url: "/api/submit" });

  const onClickSubmit = () => {
    submit({ key: "value" });
  };

  return (
    <div>
      <button onClick={onClickSubmit}>送信</button>
      { loading && <p>送信中だよ!</p>}
      { response && <p>成功したよ!</p>}
      { error && <p>エラーだよ!</p>}
    </div>
  );
};

簡単ですね。
ということで、メモでした。