1
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?

【React】react-hook-form-muiを使ったフォームの作成

Posted at

概要

npmで公開されているreact-hook-form-muiを使ってフォームを作ってみます。このライブラリは通常のreact-hook-form + MUIよりもシンプルにコーディングできるようで、npmのダウンロード数を見ると意外と利用されているような印象を持ちます。

以前にreact-hook-formとMUIを使ってフォームを作ったことがありますので、このコードと比較していきたいと思います。

前提

・Reactがインストールされていること
・MUIがインストールされていること

npm i @mui/material @emotion/react @emotion/styled

・react-hook-formとreact-hook-form-muiがインストールされていること

npm i react-hook-form react-hook-form-mui

使い方

Readmeドキュメントに記載されている通り、以下のコンポーネントが用意されていますので、これらを使ってコーディングしていくイメージかと思います。
今回の記事は一部のみ使います。

  • FormContainer
  • AutocompleteElement
  • TextFieldElement
  • SelectElement
  • MultiSelectElement
  • RadioButtonGroup
  • CheckboxButtonGroup
  • CheckboxElement
  • SwitchElement
  • PasswordElement
  • DatePickerElement
  • SliderElement
  • ToggleButtonGroupElement

サンプルコード(最小限)

react-hook-form-muiが動作する必要最小限のコードです。
このコードをもとにカスタマイズをしていきます。

"use client"
import { Button } from "@mui/material"
import React from "react"
import { FormContainer, TextFieldElement } from "react-hook-form-mui"

const page = () => {
  const submit = (data: object) => {
    console.log(data);
  }
  return (
      <FormContainer defaultValues={{ example: "" }} onSuccess={submit}>
        <TextFieldElement name="example" label="example" required/>
        <div>
          <Button type='submit' variant="contained">ログイン</Button>
        </div>
      </FormContainer>
  )
}

export default page

image.png
入力された値はsubmitメソッドの第1引数に引き渡されます。
メソッドの変数名は任意です。
image.png

比較としてreact-hook-form-muiを使わないほうのサンプルコードを以下に記載します。ほぼ同じ動作をしますが、シンプルになっていますかね

"use client"
import { Button, TextField } from "@mui/material"
import React from "react"
import { SubmitHandler, useForm } from "react-hook-form"

type Input = {
  example: string
}

const page = () => {
  const { register, handleSubmit } = useForm<Input>()
  const onSubmit: SubmitHandler<Input> = (data) => console.log(data);
  return (
    <>
      <form onSubmit={handleSubmit(onSubmit)}>
        <TextField
          id="outlined-basic"
          label="Outlined"
          {...register("example")}
        />
        <div>
          <Button type='submit' variant="contained">Contained</Button>
        </div>
      </form>
    </>
  )
}

export default page

オプション

MUIをもとにコンポーネントが作られているようで、sxやMUIが用意したスタイルを適用することはできるようです。

    <TextFieldElement 
        name="example" 
        label="example" 
        variant="standard" //MUIのText Fieldより
        sx={{ width: "600px" }}  //スタイルの適用
    />

image.png

エラーメッセージの設定

入力されていなかった場合などのエラーメッセージはすでに用意されていますが、自分でメッセージを設定したい場合は、FormErrorProviderを使うことで設定が可能です。

"use client"
import { Button } from "@mui/material"
import React from "react"
import { FormContainer, FormErrorProvider, TextFieldElement } from "react-hook-form-mui"

const page = () => {
  const submit = (data: object) => {
    console.log(data);
  }
  const errorPrams = (error: FieldError) => {
    if (error.type === 'required') {
      return '入力してください。';
    }
    return error?.message;
  }
  return (
    <FormErrorProvider onError={errorPrams}>
      <FormContainer defaultValues={{ example: "" }} onSuccess={submit}>
        <TextFieldElement 
          name="example"
          label="example"
          required
        />
        <div>
          <Button type='submit' variant="contained">ログイン</Button>
        </div>
      </FormContainer>
    </FormErrorProvider>
  )
}

export default page

image.png

完成したもの

"use client"
import { Box, Button, Container, Paper } from "@mui/material"
import React from "react"
import { FormContainer, PasswordElement, TextFieldElement } from "react-hook-form-mui"

const page = () => {
  const submit = (data: object) => {
    console.log(data);
  }
  return (
    <>
      <Container sx={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100vh" }}>
        <Paper elevation={3} sx={{ width: "600px", padding: 4 }}>

          <Box sx={{ textAlign: "center", fontSize: "24px", fontWeight: "bold" }}>ログイン</Box>
          <FormContainer defaultValues={{ email: "", password: "" }} onSuccess={submit}>
            <TextFieldElement
              name="email"
              label="Email"
              fullWidth
              required
              type="email"
              margin="normal"
            />
            <PasswordElement
              name="password"
              label="Password"
              fullWidth
              required
              margin="normal"
            />
            <div>
              <Button type='submit' variant="contained" sx={{ marginTop: "16px" }}>ログイン</Button>
            </div>
          </FormContainer>

        </Paper>
      </Container>
    </>
  )
}

export default page

image.png
image.png

比較

react-hook-form-muiを使わなかった場合のコードを比較として記載します。

"use client"
import { Box, Button, Container, Paper, TextField } from "@mui/material"
import React from "react"
import { SubmitHandler, useForm } from "react-hook-form"

type Input = {
  email: string,
  password: string
}

const page = () => {
  const { register, handleSubmit, formState: { errors }} = useForm<Input>()
  const onSubmit: SubmitHandler<Input> = (data) => console.log(data);
  return (
    <>
      <Container sx={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100vh" }}>
        <Paper elevation={3} sx={{ width: "600px", padding: 4 }}>

          <Box sx={{ textAlign: "center", fontSize: "24px", fontWeight: "bold" }}>ログイン</Box>
          <form onSubmit={handleSubmit(onSubmit)}>
            <TextField
              fullWidth
              id="outlined-basic"
              label="Email"
              type="email"
              margin="normal"
              {...register("email", { required: true })}
              error={errors.email ? true : false }
              helperText={errors.email ? "Email is required" : ""}
            />

            <TextField
              fullWidth
              id="outlined-basic"
              label="Password"
              type="password"
              margin="normal"
              {...register("password", { required: true })}
              error={errors.password ? true : false }
              helperText={errors.password ? "Password is required" : ""}
            />
            <div>
              <Button type='submit' variant="contained" sx={{ marginTop: "16px" }}>ログイン</Button>
            </div>
          </form>
          
        </Paper>
      </Container>
    </>
  )
}

export default page

まとめ

シンプルにコーディングできる分、エラー処理などのこだわった機能を追加するのは難しそうな印象を持ちました。
特にこだわりがなくシンプルに使いたい場合は、このライブラリは選択肢一つとしてよさそうかと思います。

参考

1
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
1
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?