Typescript×React×Hooks로 회원관리③Formik과 Yup에서 폼바리데이션

지난번에는 Typescript×React×Hooks 및 Firebase Authentication을 사용하여 작성한 회원 관리 앱에 Context를 활용한 상태 관리를 도입하여 앱의 규모 확대에 대한 내성을 강화했습니다. 이번에는 Formik과 Yup을 활용하여 폼 바리데이션을 추가하겠습니다.

총 3회의 내용은 아래와 같습니다.
  • Firebase Auth로 인증 기반 외출
  • Context로 앱 상태 관리
  • Formik 및 Yup에서 양식 유효성 검사

  • 사용하는 기술 요소


  • Firebase Authentication
  • Typescript
  • React
  • React Hooks
  • Context

  • Material UI
  • Formik ←NEW
  • Yup ←NEW

  • 소스 코드



    이전과의 차이 도 일단 붙여 둡니다.

    데모



    폼 밸리데이션에 의해 아래와 같은 기능이 추가되고 있습니다.
  • 필수 항목의 유효성 검사
  • 최소 문자 수의 검증
  • 밸리데이션을 통과한 경우(Valid) Submit 버튼을 클릭할 수 있게 된다



  • 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 호출
  • 다중 언어 지원
  • 헤더 및 바닥글과 같은 부품 설계
  • 로깅
  • 테스트
  • ...

  • 이렇게 생각하면 역시 어플리케이션 개발은 안쪽이 깊네요. 매일 정진입니다.

    좋은 웹페이지 즐겨찾기