8
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【React × TypeScript】フロントバリデージョンを実装してみた

Last updated at Posted at 2021-09-23

Reactを使ってフロントバリデージョンを実装する機会があったので、アウトプットします。

今回の目的

入力された値を検証し、エラーメッセージを表示させる関数を作成すること

目次

  1. 送信フォームを作成
  2. 値を検証する関数を作成
  3. 送信ボタンをクリックできなくする
  4. カスタムフック化

1. 送信フォームを作成

今回は、以下のフォームをベースに実装しております。

  • 入力されたフォームの値を管理するStateを作成
  • 入力された時、値が更新されるonchangeイベントを実装
  • 送信ボタンをクリックした時、入力している値がアラートされる
  • CSSフレームワークとして、chakra-uiを採用
送信フォームベース
App.tsx
import React, { ChangeEvent, useState } from "react";
import { ChakraProvider, Input, Button, Box } from "@chakra-ui/react" ;

export default function App() {
  const [inputPost, setInputPost] = useState<string>("")

  const onChangePost = (e: ChangeEvent<HTMLInputElement>) => {
    const post = e.target.value;
    setInputPost(post)
  }

  const onClickSubmit = () => {
    alert(inputPost)
  }

  return (
    <ChakraProvider>
      <Box m={16}>
        <Input value={inputPost} onChange={onChangePost}  w="sm" />
        <Button onClick={onClickSubmit} bg="blue.300" color="white">送信する</Button>
      </Box>
    </ChakraProvider>
  );
}

これで、入力した値がアラートされるフォームができました。

ただ、現状では以下の問題点があります。

  • 空文字でも送信できる
  • 文字数も無制限に入力できる

なので、これを制限していきたいと思います。

2.値を検証する関数を作成

検証用の関数(validateInputPost)を作成して、検証に引っ掛かった場合、エラーメッセージ を表示させます

検証内容

今回の検証内容は、以下の通りです。

  1. タイトルが空でないか
  2. タイトルが文字数を超えていないか(今回は8文字)

上記に引っかかる場合、エラー文字を表示させていきます。

プログラムの流れ

想定している流れは、以下の通りです。

  • onChangeでstateの値が更新される
  • 更新された値を検証する
  • 値が想定外だった場合、エラーメッセージを返す
  • エラーメッセージ がある場合、それを表示する

実装

1.エラーを保持するstateを作成

App.tsx
const [error, setError] = useState<string>("");

2.検証する関数を作成

App.tsx
const validateInputPost = (inputPost: string) => {
    const maxPostLength = 8;
    let error = "";
    // 制限1.空の場合
    if (!inputPost) {
      error = "投稿を入力してください";
    // 制限2.文字数が8文字より多い場合
    } else if (inputPost.length > maxPostLength) {
      error = `投稿は${maxPostLength}文字以内で入力してください`;
    }
    //検証に引っ掛かった時、エラーを保持するstateを更新
    setError(error);
  };

3.onCahgeイベント時に、検証する関数を実行

App.tsx
const onChangePost = (e: ChangeEvent<HTMLInputElement>) => {
    const post = e.target.value;
    setInputPost(post);
    validateInputPost(post) //これ
  };

4.エラーを保持するstateがエラー内容を持っている場合、エラー文字を表示させる

以下のように実装すると、エラー内容を保持している場合のみ、赤文字でエラー文が表示されます。

App.tsx

//エラーの場合: errorにエラー内容が入る
//エラーでない場合: ""が入っている = 表示されない 

  { error && 
   <Text color="red">{error}</Text>
  }

全体

App.tsx
import React, { ChangeEvent, useState } from "react";
import { ChakraProvider, Input, Button, Box, Text } from "@chakra-ui/react";

export default function App() {
  const [inputPost, setInputPost] = useState<string>("");
  const [error, setError] = useState<string>(""); // 1

  const onChangePost = (e: ChangeEvent<HTMLInputElement>) => {
    const post = e.target.value;
    setInputPost(post);
    validateInputPost(post);   // 3
  };

  const onClickSubmit = () => {
    alert(inputPost);
  };

  // 2
  const validateInputPost = (inputPost: string) => {
    const maxPostLength = 8;
    let error = "";
    if (!inputPost) {
      error = "投稿を入力してください";
    } else if (inputPost.length > maxPostLength) {
      error = `投稿は${maxPostLength}文字以内で入力してください`;
    }
    setError(error);
  };

  return (
    <ChakraProvider>
      <Box m={16}>
        <Input value={inputPost} onChange={onChangePost} w="sm" />
        <Button onClick={onClickSubmit} bg="blue.300" color="white">
          送信する
        </Button>
        {error && <Text color="red">{error}</Text>}  // 4
      </Box>
    </ChakraProvider>
  );
}

これで、エラー文字が表示されるようになります。

エラーメッセージ (空) エラーメッセージ (文字数制限)

3.送信ボタンをクリックできなくする

  • 現状だと、エラーメッセージ を表示させているだけで送信できてしまいます。
isDisabled前1 isDisabled前2
  • これでは意味がないので、送信ボタンをクリックできないようにします。今回はisDisabledを使用します。(trueの場合、ボタンがクリックできなくなります。)

  • isDisabledは、trueであればボタンがクリックできなくなります。なので、errorに文字が入っている場合、trueになるため、送信することができなくなります。

App.tsx
<Button onClick={onClickSubmit} isDisabled={error} bg="blue.300" color="white">
  送信する
</Button>

これでokです!
ボタンが少し透明になって、クリックできなくなります。

実装後

isDisabled後1 isDisabled後2
  • 最終コード
App.tsx
import React, { ChangeEvent, useState } from "react";
import { ChakraProvider, Input, Button, Box, Text } from "@chakra-ui/react";

export default function App() {
  const [inputPost, setInputPost] = useState<string>("");
  const [error, setError] = useState<string>("");

  const onChangePost = (e: ChangeEvent<HTMLInputElement>) => {
    const post = e.target.value;
    setInputPost(post);
    validateInputPost(post);
  };

  const onClickSubmit = () => {
    alert(inputPost);
  };

  const validateInputPost = (inputPost: string) => {
    const maxPostLength = 8;
    let error = "";
    if (!inputPost) {
      error = "投稿を入力してください";
    } else if (inputPost.length > maxPostLength) {
      error = `投稿は${maxPostLength}文字以内で入力してください`;
    }
    setError(error);
  };

  return (
    <ChakraProvider>
      <Box m={16}>
        <Input value={inputPost} onChange={onChangePost} w="sm" />
        <Button onClick={onClickSubmit} isDisabled={error} bg="blue.300" color="white">
          送信する
        </Button>
        {error && <Text color="red">{error}</Text>}
      </Box>
    </ChakraProvider>
  );
}

4.カスタムフック化

最後に、検証用の関数をカスタムフックとして切り出します

App.tsx
import React, { ChangeEvent, useState } from "react";
import { ChakraProvider, Input, Button, Box, Text } from "@chakra-ui/react";

import { usePostValidate } from "./useValidate";

export default function App() {
  const [inputPost, setInputPost] = useState<string>("");
  const { error, validateInputPost } = usePostValidate();

  const onChangePost = (e: ChangeEvent<HTMLInputElement>) => {
    const post = e.target.value;
    setInputPost(post);
    validateInputPost(post);
  };

  const onClickSubmit = () => {
    alert(inputPost);
  };

  return (
    <ChakraProvider>
      <Box m={16}>
        <Input value={inputPost} onChange={onChangePost} w="sm" />
        <Button
          onClick={onClickSubmit}
          isDisabled={error}
          bg="blue.300"
          color="white"
        >
          送信する
        </Button>
        {error && <Text color="red">{error}</Text>}
      </Box>
    </ChakraProvider>
  );
}
useValidate.ts
import { useState } from "react";

export const usePostValidate = () => {
  const [error, setError] = useState<string>("");

  const validateInputPost = (inputPost: string) => {
    const maxPostLength = 8;
    let error = "";
    if (!inputPost) {
      error = "投稿を入力してください";
    } else if (inputPost.length > maxPostLength) {
      error = `投稿は${maxPostLength}文字以内で入力してください`;
    }
    setError(error);
  };
  return { validateInputPost, error };
};

同じ挙動になるとOKです。

以上になります。

参考資料

8
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?