# React

> 送信中、エラー、成功の状態、フィールドエラー、任意の人間確認を備えた React のフォーム。

Vite、Remix、React Router、[Gatsby](https://ikiform.com/ja/docs/guides/gatsby.md)、Next.js のクライアントコンポーネントなど、どんな React アプリでも動きます。ブラウザーから直接送信するので、レート制限は訪問者ごとにカウントされます。

## SDK をインストールする

`ターミナル`:

```bash
npm install @ikiform/sdk
```

## 完全なフォーム

`contact-form.jsx`:

```jsx
import { challenge, submit } from "@ikiform/sdk";
import { useState } from "react";

const FORM_ID = "frm_xxxxxxxxxxxxxxxx";

export function ContactForm({ humanCheck = false }) {
  const [status, setStatus] = useState("idle");
  const [errors, setErrors] = useState({});
  const [message, setMessage] = useState("");

  async function onSubmit(event) {
    event.preventDefault();
    const data = new FormData(event.currentTarget);
    setStatus("sending");
    setErrors({});
    try {
      const turnstileToken = humanCheck ? await challenge(FORM_ID) : undefined;
      const result = await submit(FORM_ID, data, { turnstileToken });
      if (result.ok) return setStatus("sent");
      setErrors(result.error.fields ?? {});
      setMessage(result.error.message);
    } catch {
      setMessage("The human check didn't finish. Try again.");
    }
    setStatus("error");
  }

  if (status === "sent") return <p>Thanks, we got it.</p>;

  return (
    <form onSubmit={onSubmit}>
      <label>
        Email
        <input name="email" type="email" required />
      </label>
      {errors.email ? <p>{errors.email[0]}</p> : null}
      <label>
        Message
        <textarea name="message" />
      </label>
      {errors.message ? <p>{errors.message[0]}</p> : null}
      <input name="_gotcha" type="text" tabIndex={-1} autoComplete="off" hidden />
      {status === "error" && message ? <p role="alert">{message}</p> : null}
      <button disabled={status === "sending"}>Send</button>
    </form>
  );
}
```

- フォームのスパムチェックが **Ikiform** の場合は `humanCheck` を渡します。チェックがオフなら省略します。
- チェックが失敗または中断されると、`challenge` は `ChallengeError` で reject され、`catch` でメッセージに変換されます。
- SDK を使わない場合は、[JavaScript と fetch](https://ikiform.com/ja/docs/frameworks.md#fetch) のように `submit` を `fetch` に置き換えます。

## フォームアクションとして使う

React 19 では、`submit` が返す値はフォームアクションの型も満たすので、そのまま `action` に渡せます。React 内部の `$ACTION_` フィールドは送信前に除外されます。

`newsletter.jsx`:

```jsx
import { submit } from "@ikiform/sdk";

export function Newsletter() {
  return (
    <form action={(data) => submit("frm_xxxxxxxxxxxxxxxx", data)}>
      <input name="email" type="email" required />
      <button>Subscribe</button>
    </form>
  );
}
```

## 送信前にバリデーションする

`validate` は 12 種類すべてのフィールドタイプで、サーバーと同じルールとメッセージを使うので、リクエストの前にエラーを表示できます。正とするのはあくまでサーバーです。

`validate.js`:

```js
import { getSchema, validate } from "@ikiform/sdk";

const schema = await getSchema("frm_xxxxxxxxxxxxxxxx");

function check(form) {
  if (!schema.ok) return {};
  return validate(schema.schema.fields, new FormData(form));
}
```
