こんなフォームは嫌だ

この記事はクソアプリ [Advent Calendar 2021](https://qiita.com/advent-calendar/2021/kuso-app)の22日目の記事です。

世の中には嫌なことが沢山ありますが、その中の一つにフォーム入力があります。

素晴らしいフォームを皆さんに作っていただきたいので、反面教師として嫌なフォームをつくってみました。

サービスはこちら
[いらいらフォームRTA](https://www.iraira-form-rta.net/)


## 作ったもの

名前を入力するだけフォームです。
![form.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390321/59f0996e-1c64-8240-f29f-f412bd27ed3b.png)


名前は好きな文字列
それと読み方が分からないかもしれないので一応カタカナでも名前入力してもらいます。


## 使った技術

- フロントエンド Next.js/TypeScript/Tailwind CSS
- デプロイ Vercel


## こだわったところ（嫌なフォーム）

### 利用規約を最後までscrollして同意するにチェックしないとボタンを押せない

```tsx:terms.tsx
import { useState } from "react";
import styles from "../styles/terms.module.css";
interface checkProps {
  id: string;
  checked: boolean;
  onChange: VoidFunction;
}
interface Props {
  checked: boolean;
  onChange: any;
}
const CheckBox = ({ id, checked, onChange }: checkProps) => {
  return (
    <input
      id={id}
      type="checkbox"
      name="inputNames"
      checked={checked}
      onChange={onChange}
    />
  );
};

const Terms = (props: Props) => {
  const [scrollFlg, setScroll] = useState(false);

  const isScrollToggle = () => {
    const scrollTop = document?.getElementById("box")?.scrollTop;
    requestAnimationFrame(() => {
      if (scrollTop && scrollTop >= 900) {
        setScroll(true);
      }
    });
  };

  const enableChecked = () => {
    if (scrollFlg) {
      props.onChange(true);
    }
  };

  return (
    <>
      <div className="mt-24 my-2 mx-4 rounded">利用規約</div>
      <div id="box" className={styles.box} onScroll={isScrollToggle}>
        <p>このサイトは</p>
        <p>使いにくいフォーム</p>
        <p>をいかに早く</p>
        <p>攻略できるかを</p>
        <p>競うサービスです</p>
        <p className={styles.box_end}>利用規約終了</p>
      </div>
      <CheckBox
        id="1"
        checked={props.checked}
        onChange={() => enableChecked()}
      ></CheckBox>
    </>
  );
};

export default Terms;

```

途中までCSS Modulesで書いていて、最後はTailwindに変えたのでもろもろ混在してます。
（コードもクソということで許して）

##### コード読むのめんどくさい人向け
やってることはシンプルです。
利用規約の id="box"　の高さを200pxくらい,overflow: scroll;にして
中身を1000pxに指定してます。
スクロール量を取得して、ある程度の高さまで行ったらチェックを付けられるようにする仕組みです。
 

### tabIndexがめちゃくちゃでタブキーで意図したところに移動できない

```tsx:dummyTabs.tsx
import React from "react";
import styles from "../styles/dummy.module.css";
export default function Dummy() {
  const dummyArray: number[] = [...Array(200)].map((_, i) => i + 1);
  const dummyArray2: number[] = [...Array(200)].map((_, i) => i + 202);
  const dummyArray3: number[] = [...Array(200)].map((_, i) => i + 502);

  return (
    <form>
      {dummyArray.map((num) => (
        <input key={num} className={styles.dummy} tabIndex={num} />
      ))}
      {dummyArray2.map((num) => (
        <input key={num} className={styles.dummy} tabIndex={num} />
      ))}
      {dummyArray3.map((num) => (
        <input key={num} className={styles.dummy} tabIndex={num} />
      ))}
    </form>
  );
}

```

tabキーで移動させたくなかったのでtabIndexで連番のinputを量産しています。
途中でくぎっているのは間に名前の入力フォームとカタカナ名前の入力フォームを入れたかったからです。

### F8キーやコピペを検知してフォームクリア

```tsx:form.tsx

  useEffect(() => {
    document.addEventListener("keydown", escFunction, false);
    document.addEventListener("paste", reset, false);
  }, []);

  const escFunction = useCallback((event) => {
    if (event.keyCode === 119) {
      // F8が使われたら全削除
      reset();
    }
  }, []);

```

2つ目のフォームで半角カナを入力させるのですが、
F8(keyCode :119)を使った時にフォームを全削除する仕組みです。

ただ、フォーム入力中にF8を検知することができなかったので、入力後にF8を押したときのみ全削除する動きに妥協しました。
フォーム入力中にF8を検知する方法をしっていたら教えてください。


### 半角カナのバリデーション

```js:yup.custom.js

// カスタム部分
Yup.addMethod(Yup.string, "katakana", function () {
  return this.test("katakana", "半角で入力してください", (value) => {
    if (value == null || value === "") return true;
    return value.match(/^[ｧ-ﾝﾞﾟ]+$/);
  });
});

```


yupを初めて利用しました。
半角カナじゃないとエラーを返します。
カスタムが結構簡単なのでオススメ！


## 反省点

本来は名前以外の情報も入力してほしかったのですが、
怖いと思われて遊んでもらえないと嫌なので名前だけにしました。

その結果、現実に存在するリアルないらいらフォームとはかけ離れた入力フォームになってしまいました。
（名前は控えますが、いくつかイライラの参考にしたサイトがあります。）


いつか指紋認証か何かでフォーム入力の手間を省けるときがきたら良いなと思います。
つよつよエンジニアさん！お願いしますね！