it_tsumugi
@it_tsumugi (つむぎ)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

LalavelでReact-hook-formのバリデーションがうまくいかない

開発環境

laravel8
React
TypeScript
npm
React-Hook-Form
ローカルで作業中

現在の状況

Laravel x React x TypeScript x StyledComponentsでウェブアプリケーションを作成しています。
現在ログイン画面の入力フォームのバリデーションを行いたいのですが、うまくいきません。
仕様としてはメールアドレスとパスワードを空欄にした時にエラーメッセージを表示するというシンプルなものです。
material-UIのtextfieldコンポーネントにreact-hook-formで取得したエラーを表示させることでバリデーションを行いたいです。
このコードの一部はバリデーションがうまくいったSPAのコードを利用しているので、動くはずなのですが動きません。
例えばメールアドレス欄を空欄でボタンを押しても、APIのエラーコードが出力されるため、そもそもAPIを叩いてしまっています。
バリデーションのエラーは表示されません。

やったこと

React-hook-formの公式ドキュメントではContollerコンポーネントをインポートして利用していたので、そのとおりやってみたのですが動作しませんでした。console.log(errors)で中身を見てみましたが、たくさんあってよく分からなかったです。エラーメッセージの部分を短絡評価を使わずに直接文字列をいれたら表示されたので、errorsの中身が存在すれば恐らく表示されると考えています。

下記に現在書いているコードと、そのコードの元になったローカルのcreate-react-appで動作しているコードを記載しておきます。
1週間ほど詰まっているので教えていただけると助かります。

現在書いているコード

import { useState, useEffect } from "react";
import { useHistory } from "react-router";
import { useAuthContext } from "../../providers/AuthProvider";
import {
    Controller,
    NestedValue,
    SubmitHandler,
    useForm,
} from "react-hook-form";
import TextField from "@material-ui/core/TextField";
import axios from "axios";
import styled from "styled-components";
import { Button, InputBase } from "@material-ui/core";

export const Login = () => {
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");
    const { isLogin, setIsLogin } = useAuthContext();
    const history = useHistory();
    const {
        control,
        register,
        handleSubmit,
        formState: { errors },
    } = useForm<any>();

    type eventType = {
        e: React.FormEvent<HTMLFormElement>;
    };

    const login: SubmitHandler<eventType> = async (props) => {
        const { e } = props;
        e.preventDefault();

        try {
            // ログイン時にCSRFトークンを初期化
            await axios.get("/sanctum/csrf-cookie");
            try {
                const res = await axios.post("/api/login", {
                    email,
                    password,
                });
                if (res.data.result) {
                    console.log("login:ログイン成功");
                    setIsLogin(true);
                    history.push({ pathname: "/home" });
                } else {
                    console.log("login:ログイン失敗");
                    console.log(res.data.message);
                }
            } catch (err) {
                console.log("login:接続に失敗しました");
                console.log(err);
            }
        } catch (error) {
            console.log("login:CSRFトークンの初期化に失敗しました");
            console.log(error);
        }
    };

    return (
        <SComponentContainer>
            <form
                onSubmit={(e) => handleSubmit(login({ e }))}
                id="contact-form"
            >
                <STextField
                    label="メールアドレス"
                    type="email"
                    variant="filled"
                    fullWidth
                    margin="normal"
                    {...register("email", { required: true })}
                    error={Boolean(errors.email)}
                    helperText={
                        errors.email && "メールアドレスを入力してください"
                    }
                    onChange={(e) => setEmail(e.target.value)}
                />
                {errors.email && "メールアドレスを入力してください"}
                <STextField
                    variant="filled"
                    label="パスワード"
                    type="password"
                    fullWidth
                    margin="normal"
                    {...register("password", { required: true })}
                    error={Boolean(errors.password)}
                    helperText={
                        errors.password && "パスワードを入力してください"
                    }
                    onChange={(e) => setPassword(e.target.value)}
                />
                <Button type="submit" color="default" variant="contained">
                    Login
                </Button>
                {isLogin ? "ログインしています" : "ログインしていません"}
            </form>
        </SComponentContainer>
    );
};

const SComponentContainer = styled.div``;

const SButton = styled(Button)`
    background-color: blue;
    color: white;
`;

const STextField = styled(TextField)`
    background-color: white;
    color: black;
    .MuiInputLabel-root {
        background-color: skyblue;
        ::placeholder {
            color: red;
        }
        /* color: black; */
    }
`;

バリデーションがうまくいっているので参考にしたコード

import { useForm } from "react-hook-form";
import { sendForm } from "emailjs-com";
import { VFC } from "react";
import styled from "styled-components";
import media from "../../assets/styles/media";

import Button from "@material-ui/core/Button";
import TextField from "@material-ui/core/TextField";

import { PageTitle } from "../atoms/PageTitle";

export const Contact: VFC = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm();

  const sendMail = (e: React.ChangeEvent<HTMLFormElement>) => {
    e.preventDefault();
    sendForm(
      `${process.env.REACT_APP_SERVICE_ID}`,
      `${process.env.REACT_APP_TEMPLATE_ID}`,
      e.target,
      `${process.env.REACT_APP_USER_ID}`
    ).then(
      (response) => {
        console.log("SUCCESS!", response.status, response.text);
      },
      (error) => {
        console.log("FAILED...", error);
      }
    );
    window.alert("メールを送信しました。");
    e.target.reset();
  };

  return (
    <SComponentContainer>
      <PageTitle>CONTACT</PageTitle>
      <SText>
        お気軽に下記フォームより必須事項をご記入の上ご連絡ください。
      </SText>
      <form onSubmit={handleSubmit(sendMail)} id="contact-form">
        <STextField
          variant="filled"
          label="件名(必須)"
          type="text"
          fullWidth
          margin="normal"
          {...register("subject", { required: true })}
          error={Boolean(errors.subject)}
          helperText={errors.subject && "件名を入力してください"}
        />
        <STextField
          variant="filled"
          label="氏名(必須)"
          type="text"
          fullWidth
          margin="normal"
          {...register("name", { required: true })}
          error={Boolean(errors.name)}
          helperText={errors.name && "氏名を入力してください"}
        />
        <STextField
          variant="filled"
          label="返信用メールアドレス(必須)"
          type="email"
          fullWidth
          margin="normal"
          {...register("email", { required: true })}
          error={Boolean(errors.email)}
          helperText={errors.email && "メールアドレスを入力してください"}
        />

        <STextField
          variant="filled"
          label="お問い合わせ内容(必須)"
          type="text"
          fullWidth
          margin="normal"
          {...register("message", { required: true })}
          error={Boolean(errors.message)}
          helperText={errors.message && "お問い合わせ内容を入力して下さい。"}
          multiline
          rows="8"
        />
        <SButton variant="contained" color="default" type="submit">
          送信
        </SButton>
      </form>
    </SComponentContainer>
  );
};

const SComponentContainer = styled.div`
  width: 100%;
  margin: 0 auto;
  max-width: 80vw;
  text-align: center;

  padding: 80px 0 0;
  ${media.lg`
  padding: 0 0 60px;
  `}
  ${media.md`
  padding: 10px 0 40px;
  `}
`;

const SText = styled.p`
  font-size: 16px;
  ${media.lg`
  font-size: 14px;
  `}
  ${media.md`
  font-size: 12px;
  `}
`;

const STextField = styled(TextField)`
  background-color: white;
  ::placeholder {
    color: gray;
  }
`;

const SButton = styled(Button)`
  margin-top: 10;
  float: left;
`;
0

No Answers yet.

Your answer might help someone💌