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;
`;