Help us understand the problem. What is going on with this article?

Typescript×React×Hooksで会員管理③Formik とYupでフォームバリデーション

前回はTypescript×React×Hooks 及び Firebase Authentication を用いて作成している会員管理アプリに、Contextを活用した状態管理を導入し、アプリの規模拡大に対する耐性を強化しました。今回はFormikとYupを活用してフォームバリデーションを追加していきます。

全 3 回の内容は下記です。

  1. Firebase Auth で認証基盤外出し
  2. Context でアプリの状態管理
  3. Formik と Yup でフォームバリデーション

利用している技術要素

  • Firebase Authentication
  • Typescript
  • React
  • React Hooks
    • Context
  • Material UI
  • Formik  ←NEW
  • Yup  ←NEW

ソースコード

https://github.com/motoitanigaki/typescript-react-hooks-firebase_authentication-boilerplate/tree/%2Bvalidation

前回との差分 も一応貼っておきます。

デモ

フォームバリデーションにより下記のような機能が追加されています。

  • 必須項目のバリデーション
  • 最小文字数のバリデーション
  • バリデーションを通った(Valid)場合Submitボタンをクリックできるようになる

demo2.gif

React アプリのポイント解説

前回との差分中心に説明します。

いくつかライブラリが追加されていますが、これまで同様ソースコードからそのままyarn startすれば動くと思います。

会員登録用のSignup.tsxとログイン用のLogin.tsxそれぞれほとんど同じような変更を加えているので、Signup.tsxを中心に見ていきます。

Signup.tsx
import { Field, Form, Formik } from "formik";
// Material UIのために、formikのFormコンポーネントに渡す必要がある。 @material_ui/core にも同名のものがあり注意
import { TextField } from "formik-material-ui";
import React, { Fragment, useContext, useEffect } from "react";
import * as Yup from "yup";

import {
  Button,
  Container,
  FormControl,
  Grid,
  Link,
  Typography,
  LinearProgress
} from "@material-ui/core";

import { AuthContext } from "../Auth";
import auth from "../firebase";

// Yupでバリデーション用のスキーマを定義。Login.tsxでも利用するのでexportしている
export const AuthSchema = Yup.object().shape({
  email: Yup.string()
    .email()
    .required(),
  password: Yup.string()
    .min(6)
    .required()
});

const Signup = (props: any) => {
  const { currentUser } = useContext(AuthContext);

  useEffect(() => {
    currentUser && props.history.push("/");
  }, [currentUser]);

  return (
    <Fragment>
      <Container>
        <Grid container>
          <Grid item md={4}></Grid>
          <Grid item md={4}>
            <Formik
              // フォームの初期値を定義
              initialValues={{ email: "", password: "" }}
              // Yupで定義したスキーマを利用
              validationSchema={AuthSchema}
         // フォームSubmit時のイベントを定義。Firebase APIを呼んでいる
              onSubmit={async value => {
                try {
                  await auth.createUserWithEmailAndPassword(
                    value.email,
                    value.password
                  );
                  props.history.push("/login");
                } catch (error) {
                  alert(error.message);
                }
              }}
              // フォームの描画を定義。今回はFormikで持つオブジェクトを3つ渡してフォーム内で利用している
         // submitForm:上記で定義したフォームSubmit時のイベント
         // isSubmitting:Submit中かどうかの状態判定
         // isValid:フォームがValidでSubmit可能化の状態判定
              render={({ submitForm, isSubmitting, isValid }) => (
                <Form>
                  // Submit中にプログレスバーを表示
                  {isSubmitting && <LinearProgress />}
                  <FormControl margin="normal" fullWidth>
                    <Field
                      style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
                      name="email"
                      label="E-mail"
                      fullWidth
                      variant="outlined"
                      component={TextField}
                    />
                  </FormControl>
                  <FormControl fullWidth>
                    <Field
                      style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
                      name="password"
                      label="Password"
                      fullWidth
                      variant="outlined"
                      type="password"
                      component={TextField}
                    />
                  </FormControl>
                  <FormControl fullWidth>
                    <Button
                      fullWidth
                      // Submit時のイベントを紐付け
                      onClick={submitForm}
                      style={{ marginTop: "0.5em", marginBottom: "0.5em" }}
                      type="submit"
                      // フォームがValidでない or Submit中の場合、SubmitボタンをDisabledにする
                      disabled={!isValid || isSubmitting}
                    >
                      Sign up
                    </Button>
                    <Typography align="center">
                      <Link href="/login">to login</Link>
                    </Typography>
                  </FormControl>
                </Form>
              )}
            />
          </Grid>
          <Grid item md={4}></Grid>
        </Grid>
      </Container>
    </Fragment>
  );
};

export default Signup;

コード内にコメントを書いたので、読めば何をしているかわかるかと思います。

Material UIとFormikをあわせて利用している例があまりなかったので、動かすまで苦労しました。特にフォームの各フィールドにはformikが提供するFormを利用し、component属性にformik-material-uiが提供するTextFieldを渡してあげる部分がわかりにくかったのを記憶しています。

最後に

3回にわけて、Typescript×React×Firebase Authenticationで会員管理ができるアプリを作り、その上に機能追加をしていけるような骨組みを構築しました。

より本格的なアプリケーションにするためには、例えば下記要素なんかが考慮されると思います。

  • APIコール
  • 複数言語対応
  • ヘッダーやフッターといったパーツの設計
  • ロギング
  • テスト
  • ...

こう考えるとやはりアプリケーション開発は奥が深いですね。日々精進です。

mtitg
データサイエンスの企業でWebエンジニアやってます
datamix
データサイエンスに関わる最適なサービスを継続的に提供することで、企業・地域・社会に属するひとりひとりが、客観的に意思決定する力を高め、自由に、そして平等に活躍できる世界を実現します。
https://datamix.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした