LoginSignup
13
10

More than 3 years have passed since last update.

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

Posted at

前回は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

ソースコード

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

デモ

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

  • 必須項目のバリデーション
  • 最小文字数のバリデーション
  • バリデーションを通った(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コール
  • 複数言語対応
  • ヘッダーやフッターといったパーツの設計
  • ロギング
  • テスト
  • ...

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

13
10
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
13
10