0
0

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 1 year has passed since last update.

【Typescript + React】ZodとMaterial UIを使って入力のバリデーションを実装する

Posted at

今回実装するもの

画面収録-2023-10-29-19.46.33.gif

validationはzodで、UIはmaterial UIを使っていきます。

ライブラリインストール

npm install zod
npm install @mui/material @emotion/react @emotion/styled

Material UIはreactのUIフレームワークです。
公式ドキュメントに色々UIコンポーネントの例が掲載されていて、コピペするだけできれいなUIが実装できてとても便利です。

zodは型検証ライブラリです。
zodに関して詳しく知りたい方はこの記事が勉強になると思います。

実装

UIの実装

まずはUIを実装してしまいましょう。
material UIコンポーネントを使って雑に実装します。

App.tsx
import { Box, Button, TextField } from '@mui/material';

function App() {

  return (
    <>
      <Box textAlign={'center'} margin={'20px 0'}>
        <TextField
          label="名前"
          variant="outlined"
          required
        />
        <Box>
          <Button>提出</Button>
        </Box>
      </Box>
      
    </>
  );
}

これで以下のようになると思います。

スクリーンショット 2023-10-29 20.07.54.png

以下がそれぞれのオプションの説明です。

オプション 概要
label 表示するラベルの設定
variant 表示デザインの設定(詳しくは公式ドキュメント参照)
required 必須項目かの設定(これをtrueにすると * がつきます)

user変数の定義

それではここで入力した値を変数に束縛します。

App.tsx
import { Box, Button, TextField } from '@mui/material';
import { ChangeEvent, useState } from 'react';
import {z} from 'zod'

const User = z.object({
 name: z.string().min(1)
})
type User = z.infer<typeof User>

function App() {

 const inputHandler = (event: ChangeEvent<HTMLInputElement>) => {
   setUser({
     name: event.target.value
   })
 }

 const [user, setUser] = useState<User>()


 return (
   <>
     <Box textAlign={'center'} margin={'20px 0'}>
       <TextField
         autoComplete='off'
         label="名前"
         variant="outlined"
         required
         onChange={inputHandler}
       />
       <Box>
         <Button onClick={submitHandler}>提出</Button>
       </Box>
     </Box>
     
   </>
 );
}

export default App;

ここで、zodがでてきました。
今はnameしかないですが、実際使う時はemailやpasswordなどの他の要素もあるかもなので、User型はobject型にしてみています。
そして、nameは1文字以上のstring型に設定しています。

あとは onChangeでTextFieldに値が入力されたら発火するhandlerを作ってその中でsetUserを用いてe.target.valueをuserに束縛しました。

バリデーションの実装

最後にバリデーションを実現します。
先ほど、User型に変数を束縛したのであとは先ほど入れた値がUser型に一致しているか検証してあげればいいだけです。

App.tsx
import { Box, Button, TextField } from '@mui/material';
import { ChangeEvent, useState } from 'react';
import {z} from 'zod'

const User = z.object({
 name: z.string().min(1)
})
type User = z.infer<typeof User>

function App() {
 const inputHandler = (event: ChangeEvent<HTMLInputElement>) => {
   setUser({
     name: event.target.value
   })
 }

 const submitHandler = () => {
   const parseResult = User.safeParse(user)
   if (!parseResult.success) {
     setError(true)
   }else{
     setError(false)
   }
 }

 const [user, setUser] = useState<User>()
 const [error, setError] = useState<boolean>()

 return (
   <>
     <Box textAlign={'center'} margin={'20px 0'}>
       <TextField
         autoComplete='off'
         label="名前"
         variant="outlined"
         required
         name="name"
         onChange={inputHandler}
         helperText={error ? '1文字以上入力してください' : ''}
         error={error}

       />
       <Box>
         <Button onClick={submitHandler}>提出</Button>
       </Box>
     </Box>
     
   </>
 );
}

export default App;

buttonをクリックするとsubmitHandlerが発火して、zodの型検証をしてくれます。

zodで定義した型に対してsafeParseしてあげると、パース結果がsuccessにてbooleanで渡されます。
(User.parseとすることもできますが、これはパースに失敗するとエラーを投げるのでtry, catchなどで例外処理が必要になります)

こうすることによって、パースに失敗したらerrorフラグをtrueにします。

そして、TextFieldの中でerrorがtrueのときにhelperTextを表示して、errorオプションをtrueに設定します。

errorオプションをtreuにすることで枠が赤くなってくれます。Material UI様様です。

helperTextは追加テキストを表示してくれます。Material UI様様です。

これで、validationを実装することができました!

終わりに

今回はこんな感じでバリデーションを実装してみました。
こんな書き方のほうがかっこいいとか、こんな方法もあるとか、ここ間違えてるよとかご意見ある方いらっしゃったらコメントください。

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?