質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

1回答

1556閲覧

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

it-tsumugi

総合スコア11

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2021/09/02 03:40

#開発環境
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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

最近自分も同じような事でつまづいたのでもし解決策になれば嬉しいです。
https://teratail.com/questions/354789

registerメソッドに関してはinput要素に対して指定するかと思います。
textfieldコンポーネントはinput要素ではなくinput要素を含んだdiv要素になります。

jsx

1//すごくざっくりですが 2textfield != <input /> 3textfield = <div> <input /> </div>

なので今のコードだとdiv要素に対してregisterメソッドを指定してしまっている状態になります。
textfieldコンポーネントのinput要素に対して指定したい場合はinputPropsを使用して指定します。

jsx

1<STextField 2 label="メールアドレス" 3 type="email" 4 variant="filled" 5 fullWidth 6 margin="normal" 7/////////////////////////////////////////////////////////////////// 8 //↓ここの部分をこうする{...register("email", { required: true })} 9 inputProps={...register("email", { required: true })} 10/////////////////////////////////////////////////////////////////// 11 error={Boolean(errors.email)} 12 helperText={ 13 errors.email && "メールアドレスを入力してください" 14 } 15 onChange={(e) => setEmail(e.target.value)} 16/>

これでバリデーションが行われてhandleSubmitにも入力した値が渡されると思います。
errorやhelperText等の指定についてはどの要素に対して指定すればいいのか調べてみてください!

また余談ですがonChangeを使用して入力の値をstateに更新されていますがuseFormにwatchという機能があり値を監視してくれるものがあるのでそちらを使用して値を更新してもよろしいかもしれません!
良かったら使用してみてください!

投稿2021/09/02 04:13

hiroki88

総合スコア66

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

it-tsumugi

2021/09/06 05:05

試しましたが改善しませんでした、そのあともいろいろと調べてみたところ、login関数をもっとシンプルな関数にした場合動いたのでこの関数が原因だと思うのですが解決できていない状態です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問