#開発環境
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週間ほど詰まっているので教えていただけると助かります。
現在書いているコード
React
1import { useState, useEffect } from "react"; 2import { useHistory } from "react-router"; 3import { useAuthContext } from "../../providers/AuthProvider"; 4import { 5 Controller, 6 NestedValue, 7 SubmitHandler, 8 useForm, 9} from "react-hook-form"; 10import TextField from "@material-ui/core/TextField"; 11import axios from "axios"; 12import styled from "styled-components"; 13import { Button, InputBase } from "@material-ui/core"; 14 15export const Login = () => { 16 const [email, setEmail] = useState(""); 17 const [password, setPassword] = useState(""); 18 const { isLogin, setIsLogin } = useAuthContext(); 19 const history = useHistory(); 20 const { 21 control, 22 register, 23 handleSubmit, 24 formState: { errors }, 25 } = useForm<any>(); 26 27 type eventType = { 28 e: React.FormEvent<HTMLFormElement>; 29 }; 30 31 const login: SubmitHandler<eventType> = async (props) => { 32 const { e } = props; 33 e.preventDefault(); 34 35 try { 36 // ログイン時にCSRFトークンを初期化 37 await axios.get("/sanctum/csrf-cookie"); 38 try { 39 const res = await axios.post("/api/login", { 40 email, 41 password, 42 }); 43 if (res.data.result) { 44 console.log("login:ログイン成功"); 45 setIsLogin(true); 46 history.push({ pathname: "/home" }); 47 } else { 48 console.log("login:ログイン失敗"); 49 console.log(res.data.message); 50 } 51 } catch (err) { 52 console.log("login:接続に失敗しました"); 53 console.log(err); 54 } 55 } catch (error) { 56 console.log("login:CSRFトークンの初期化に失敗しました"); 57 console.log(error); 58 } 59 }; 60 61 return ( 62 <SComponentContainer> 63 <form 64 onSubmit={(e) => handleSubmit(login({ e }))} 65 id="contact-form" 66 > 67 <STextField 68 label="メールアドレス" 69 type="email" 70 variant="filled" 71 fullWidth 72 margin="normal" 73 {...register("email", { required: true })} 74 error={Boolean(errors.email)} 75 helperText={ 76 errors.email && "メールアドレスを入力してください" 77 } 78 onChange={(e) => setEmail(e.target.value)} 79 /> 80 {errors.email && "メールアドレスを入力してください"} 81 <STextField 82 variant="filled" 83 label="パスワード" 84 type="password" 85 fullWidth 86 margin="normal" 87 {...register("password", { required: true })} 88 error={Boolean(errors.password)} 89 helperText={ 90 errors.password && "パスワードを入力してください" 91 } 92 onChange={(e) => setPassword(e.target.value)} 93 /> 94 <Button type="submit" color="default" variant="contained"> 95 Login 96 </Button> 97 {isLogin ? "ログインしています" : "ログインしていません"} 98 </form> 99 </SComponentContainer> 100 ); 101}; 102 103const SComponentContainer = styled.div``; 104 105const SButton = styled(Button)` 106 background-color: blue; 107 color: white; 108`; 109 110const STextField = styled(TextField)` 111 background-color: white; 112 color: black; 113 .MuiInputLabel-root { 114 background-color: skyblue; 115 ::placeholder { 116 color: red; 117 } 118 /* color: black; */ 119 } 120`; 121
バリデーションがうまくいっているので参考にしたコード
React
1import { useForm } from "react-hook-form"; 2import { sendForm } from "emailjs-com"; 3import { VFC } from "react"; 4import styled from "styled-components"; 5import media from "../../assets/styles/media"; 6 7import Button from "@material-ui/core/Button"; 8import TextField from "@material-ui/core/TextField"; 9 10import { PageTitle } from "../atoms/PageTitle"; 11 12export const Contact: VFC = () => { 13 const { 14 register, 15 handleSubmit, 16 formState: { errors }, 17 } = useForm(); 18 19 const sendMail = (e: React.ChangeEvent<HTMLFormElement>) => { 20 e.preventDefault(); 21 sendForm( 22 `${process.env.REACT_APP_SERVICE_ID}`, 23 `${process.env.REACT_APP_TEMPLATE_ID}`, 24 e.target, 25 `${process.env.REACT_APP_USER_ID}` 26 ).then( 27 (response) => { 28 console.log("SUCCESS!", response.status, response.text); 29 }, 30 (error) => { 31 console.log("FAILED...", error); 32 } 33 ); 34 window.alert("メールを送信しました。"); 35 e.target.reset(); 36 }; 37 38 return ( 39 <SComponentContainer> 40 <PageTitle>CONTACT</PageTitle> 41 <SText> 42 お気軽に下記フォームより必須事項をご記入の上ご連絡ください。 43 </SText> 44 <form onSubmit={handleSubmit(sendMail)} id="contact-form"> 45 <STextField 46 variant="filled" 47 label="件名(必須)" 48 type="text" 49 fullWidth 50 margin="normal" 51 {...register("subject", { required: true })} 52 error={Boolean(errors.subject)} 53 helperText={errors.subject && "件名を入力してください"} 54 /> 55 <STextField 56 variant="filled" 57 label="氏名(必須)" 58 type="text" 59 fullWidth 60 margin="normal" 61 {...register("name", { required: true })} 62 error={Boolean(errors.name)} 63 helperText={errors.name && "氏名を入力してください"} 64 /> 65 <STextField 66 variant="filled" 67 label="返信用メールアドレス(必須)" 68 type="email" 69 fullWidth 70 margin="normal" 71 {...register("email", { required: true })} 72 error={Boolean(errors.email)} 73 helperText={errors.email && "メールアドレスを入力してください"} 74 /> 75 76 <STextField 77 variant="filled" 78 label="お問い合わせ内容(必須)" 79 type="text" 80 fullWidth 81 margin="normal" 82 {...register("message", { required: true })} 83 error={Boolean(errors.message)} 84 helperText={errors.message && "お問い合わせ内容を入力して下さい。"} 85 multiline 86 rows="8" 87 /> 88 <SButton variant="contained" color="default" type="submit"> 89 送信 90 </SButton> 91 </form> 92 </SComponentContainer> 93 ); 94}; 95 96const SComponentContainer = styled.div` 97 width: 100%; 98 margin: 0 auto; 99 max-width: 80vw; 100 text-align: center; 101 102 padding: 80px 0 0; 103 ${media.lg` 104 padding: 0 0 60px; 105 `} 106 ${media.md` 107 padding: 10px 0 40px; 108 `} 109`; 110 111const SText = styled.p` 112 font-size: 16px; 113 ${media.lg` 114 font-size: 14px; 115 `} 116 ${media.md` 117 font-size: 12px; 118 `} 119`; 120 121const STextField = styled(TextField)` 122 background-color: white; 123 ::placeholder { 124 color: gray; 125 } 126`; 127 128const SButton = styled(Button)` 129 margin-top: 10; 130 float: left; 131`; 132
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/09/06 05:05