🥷
[React Native] rect-hook-formとvalibotでバリデーションを実装する
はじめに
この記事では、React Nativeでreact-hook-formとvalibotを使用して簡単にフォームバリデーションを実装する方法について解説します。
今回はよくあるログイン画面で使われそうなバリデーションを実装していきます。
完成した動画
バリデーションエラーの例 | 成功した例 |
---|---|
![]() |
![]() |
プロジェクトのセットアップ
まず、必要なパッケージをインストールします。
- valibot
npm install valibot
- react-hook-formとresolvers
npm install @hookform/resolvers react-hook-form
Schemaの作成
Schemaを作成します。
名前とメールとパスワードを入力するフォームのバリデーションを作成します。
import * as v from "valibot";
export const LoginSchema = v.object({
name: v.pipe(v.string(), v.nonEmpty("This field is required")),
email: v.pipe(v.string(), v.nonEmpty("This field is required"), v.email("The email address is not valid")),
password: v.pipe(
v.string(),
v.nonEmpty("This field is required"),
v.minLength(8, "The password must be at least 8 characters long"),
),
});
このスキーマでは以下のバリデーションルールを定義しています:
-
name
: 文字列で、空文字列は許可しない -
email
: 文字列で、空文字列は許可せず、有効なメールアドレス形式であることを確認 -
password
: 文字列で、空文字列は許可せず、最小8文字以上であることを確認
これだけでバリデーションを行うことができます。
フォームコンポーネントの作成
フォームコンポーネントを作成します。
全体のコード
import { LoginSchema } from "@/schema/form";
import { valibotResolver } from "@hookform/resolvers/valibot";
import { Controller, useForm } from "react-hook-form";
import { KeyboardAvoidingView, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native";
export default function Login() {
const {
control,
handleSubmit,
formState: { errors, isValid },
} = useForm({
resolver: valibotResolver(LoginSchema),
mode: "onBlur",
defaultValues: {
name: "",
email: "",
password: "",
},
});
const onSubmit = (data: any) => {
console.log(data);
};
return (
<KeyboardAvoidingView style={styles.container} behavior="padding">
<View style={styles.form}>
<Text>Name</Text>
<Controller
control={control}
name="name"
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
onChangeText={onChange}
onBlur={onBlur}
value={value}
placeholder="Name"
style={styles.input}
></TextInput>
)}
/>
<Text style={styles.errorText}>{errors.name?.message}</Text>
</View>
<View style={styles.form}>
<Text>Email</Text>
<Controller
control={control}
name="email"
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
keyboardType="email-address"
onChangeText={onChange}
onBlur={onBlur}
value={value}
placeholder="Email"
style={styles.input}
></TextInput>
)}
/>
<Text style={styles.errorText}>{errors.email?.message}</Text>
</View>
<View style={styles.form}>
<Text>Password</Text>
<Controller
control={control}
name="password"
render={({ field: { onChange, onBlur, value } }) => (
<TextInput
secureTextEntry
onChangeText={onChange}
onBlur={onBlur}
value={value}
placeholder="Password"
style={styles.input}
></TextInput>
)}
/>
<Text style={styles.errorText}>{errors.password?.message}</Text>
</View>
<TouchableOpacity
onPress={handleSubmit(onSubmit)}
disabled={!isValid}
style={[styles.button, isValid ? styles.buttonEnabled : styles.buttonDisabled]}
activeOpacity={0.7}
>
<Text style={[styles.buttonText, isValid ? styles.buttonTextEnabled : styles.buttonTextDisabled]}>
Submit
</Text>
</TouchableOpacity>
</KeyboardAvoidingView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#FFFFFF",
padding: 20,
},
form: {
gap: 10,
},
input: {
width: "100%",
height: 40,
borderWidth: 1,
borderColor: "gray",
borderRadius: 5,
padding: 10,
},
errorText: {
color: "red",
},
button: {
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 8,
alignItems: "center",
marginTop: 20,
},
buttonEnabled: {
backgroundColor: "#007AFF",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
buttonDisabled: {
backgroundColor: "#CCCCCC",
shadowOpacity: 0,
elevation: 0,
},
buttonText: {
fontSize: 16,
fontWeight: "600",
},
buttonTextEnabled: {
color: "white",
},
buttonTextDisabled: {
color: "#666666",
},
});
ポイント
1. useFormの設定
まず、useForm
フックを使用してフォームの状態管理を設定します:
const {
control,
handleSubmit,
formState: { errors, isValid },
} = useForm({
resolver: valibotResolver(LoginSchema),
mode: "onBlur",
defaultValues: {
name: "",
email: "",
password: "",
},
});
主な設定項目:
-
resolver
: valibotResolverを使用して先ほど作成したSchemaを設定 -
mode
: "onBlur"でフォーカスが外れた時にバリデーションを実行 -
defaultValues
: フォームの初期値を設定
2. フォームフィールドの実装
各フィールドはController
コンポーネントを使用して実装します:
<View style={styles.form}>
<Text>Name</Text>
<Controller
control={control}
name="name"
render={({ field: { onChange, onBlur, value } }) => (
<TextInput onChangeText={onChange} onBlur={onBlur} value={value} placeholder="Name" style={styles.input} />
)}
/>
<Text style={styles.errorText}>{errors.name?.message}</Text>
</View>
ポイント:
- react-hook-formの
Controller
コンポーネントでフォームフィールドをラップ -
field
オブジェクトから必要な関数と値を取得 - エラーメッセージを表示するための
errors
オブジェクトの使用
エラーはerrors
オブジェクトに格納されています。
Schemaで定義したバリデーションルールに違反した場合、エラーメッセージが表示されます。
<Text style={styles.errorText}>{errors.name?.message}</Text>
3. 送信ボタンの実装
最後に送信ボタンは、バリデーションの状態に応じて見た目を変更します:
<TouchableOpacity
onPress={handleSubmit(onSubmit)}
disabled={!isValid}
style={[styles.button, isValid ? styles.buttonEnabled : styles.buttonDisabled]}
activeOpacity={0.7}
>
<Text style={[styles.buttonText, isValid ? styles.buttonTextEnabled : styles.buttonTextDisabled]}>Submit</Text>
</TouchableOpacity>
ポイント:
-
isValid
の状態に応じてボタンのスタイルを変更 -
handleSubmit
でフォームの送信を処理 -
disabled
プロパティでバリデーションエラー時にボタンを無効化
参考
まとめ
この記事では、React Nativeでのフォームバリデーションの実装方法について解説しました。
実際のコードはGitHubリポジトリで確認できます。
宣伝👻
福岡を拠点にフリーランスとしてアプリ開発をしています。
一番得意なのはネイティブiOSアプリ開発ですが、FlutterやReact Nativeアプリ開発もやっています。
Discussion