この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、こんばんわ。 「クラスメソッドにジョインして、知識をいっぱい吸収出来て喜びを感じています」 CX 事業本部 Delivery 部 MAD グループ@札幌の hiro です。
今回も、前回の React Native 記事に味を占めて、React Native 連投します。
はじめに
React Native でネイティブアプリを作成し、フォーム画面を作った時にフォームのバリデーション処理を入れなければ、 と思ったときにやった内容を記述します。 フォームのバリデーション処理は、 Formikなどもありますが、
今回は、 react-hook-formとyupを 組み合わせてバリデーション処理を実施していきました。
内容
React Native の環境は良しなに、作成よろしくお願いいたします! 以下記事など参考にしつつ、React Native for Webを利用して環境を構築しました。 大変参考になるので、一読を!
https://dev.classmethod.jp/articles/react-native-for-web-with-typescript-while-referring-to-the-official-introduction/
ライブラリのインストール
今回必要になるライブラリのインストールをします。
- React Hook Form
yarn add react-hook-form
- yup
yarn add yup
動作確認
以下のように、条件を入力するとバリデーションチェックをしてくれるようになっています。
フォーム部分
今回は、ログインフォームのバリデーション処理を加える前提で記述します。
◇ ファイル構成
以下のファイル構成で、記述します。
src
┗ App.tsx・・・・・・・・ログインなどをする際のフォーム画面の表示
┣ component/
┃ ┗ TestInputComponent.tsx・・・フォーム入力部分の表示
┗ schema/
┗ testInputSchema.ts・・・・・バリデーション処理管理部分
◇ フォーム画面部分
簡単にログイン画面表示部分を以下のように記述しています。 hudleSumitが実行されることでバリデーションチェック処理が走ります。
ここで使用されている「react-hook-form」の「Control」や「useForm」などは、 以下のリンクにより詳細に記述されています。
以下が実際のファイル内容になります。
App.tsx
import React from "react";
import { View, Text, StyleSheet, Pressable } from "react-native";
import { useForm, Control, FieldValues, SubmitHandler, SubmitErrorHandler } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { TestInputComponent } from "./component/TestInputComponent";
import { testInputSchema } from "./schema/testInputSchema";
type FormDataInfo = {
email: string;
password: string;
};
export const App = () => {
const { control, handleSubmit } = useForm<FormDataInfo>({
resolver: yupResolver(testInputSchema),
});
const onSubmit: SubmitHandler<FormDataInfo> = (data: any, e: any) => console.log(data, e);
const onError: SubmitErrorHandler<FormDataInfo> = (errors: any, e: any) => console.log(errors, e);
return (
<View style={styles.container}>
<TestInputComponent
control={control as unknown as Control<FieldValues>}
areaName="email"
label="メールアドレス"
placeholder="メールアドレス"
autoCompleteType="email"
autoCapitalize="none"
style={styles.input}
/>
<TestInputComponent
control={control as unknown as Control<FieldValues>}
areaName="password"
label="パスワード"
placeholder="パスワード"
autoCompleteType="password"
secureTextEntry
style={styles.input}
/>
<Pressable
style={styles.button}
onPress={() => handleSubmit(onSubmit, onError)()}
>
<Text style={styles.text}>BUTTON</Text>
</Pressable>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginHorizontal: 100,
paddingTop: 22,
},
input: {
shadowOpacity: 0.5,
shadowRadius: 3,
shadowOffset: {
height: 0,
width: 0,
},
elevation: 2,
marginTop: 30,
paddingVertical: 20,
paddingHorizontal: 20,
},
button: {
marginTop: 30,
paddingVertical: 20,
alignItems: "center",
justifyContent: "center",
paddingHorizontal: 32,
borderRadius: 4,
elevation: 3,
backgroundColor: "blue",
},
text: {
fontSize: 16,
lineHeight: 21,
fontWeight: "bold",
letterSpacing: 0.25,
color: "white",
},
});
export default App;
◇ フォーム入力部分
次にフォーム入力表示部分を以下のように記述しています。 入力された値を参考に、バリデーションエラーが発生した際の状況などを表示するようにしています。
以下が実際のファイル内容になります。
TestInputComponent.tsx
import React from "react";
import {
TextInput,
TextInputProps,
Text,
View,
StyleSheet,
} from "react-native";
import {
Controller,
Control,
DeepMap,
FieldValues,
FieldError,
} from "react-hook-form";
interface Props extends TextInputProps {
control: Control<any>;
areaName: string;
defaultValue?: any;
label: string;
autoCompleteType: string;
}
export const TestInputComponent: React.FC<Props> = ({
control,
areaName,
defaultValue,
...props
}) => {
return (
<Controller
control={control}
name={areaName}
defaultValue={defaultValue}
render={({
field: { onChange, value, onBlur, name },
formState: { errors },
}) => (
<View>
<TextInput
// このpropsにautoCompleteTypeなど諸々乗っかってくる
{...props}
value={value || ""}
onBlur={onBlur}
onChangeText={onChange}
/>
{/* バリエーションエラー表示 */}
{errors[name] && (
<Text style={styles.text}>
{(errors[name] as DeepMap<FieldValues, FieldError>)?.message}
</Text>
)}
</View>
)}
/>
);
};
const styles = StyleSheet.create({
text: {
color: "red",
},
});
◇ バリデーション処理部分
次にバリデーション処理部分を以下のように記述しています。 よくあるバリデーションの内容もコメントアウトして記述しています。 パスワードが一致しないことなどなど。
yup.object()と.shape()は以下のような感じです。
- yup.object()
バリデーション判定対象の入力値が、オブジェクトで提供されることを期待する定義
- .shape()
バリデーションしたいデータ構造を.shape()で定義
以下が実際のファイル内容になります。
testInputSchema.ts
import * as yup from "yup";
// スキーマを定義
// inputのvalue値のエラー条件を定義
export const testInputSchema = yup.object().shape({
email: yup
.string()
.lowercase()
.email("正しいメールアドレスを入力してください。")
.required("メールアドレスは必須項目です。"),
password: yup
.string()
.matches(/(?=.*[a-z])/, "小文字を含めてください。")
.matches(/(?=.*[A-Z])/, "大文字を含めてください。")
.matches(/(?=.*[0-9])/, "数字を含めてください。")
.min(8, "最低8文字含めてください。")
.required("パスワードは必須項目です。"),
/**
* よくある他のバリデーションチェック例
*/
// メールアドレス確認用の入力をチェックする用
//checkEmail: yup
// .string()
// .lowercase()
// .email('正しいメールアドレスを入力してください。')
// .test('emails-match', '入力されたメールアドレスが一致しません。', function (value) {
// return value === this.parent.email;
// })
// .required('メールアドレス確認は必須項目です。'),
// かな入力をチェックする用
// nameKana: yup
// .string()
// .max(25, '最大25文字です。')
// .test('katakana-checker', 'カタカナで入力して下さい。', function (value: any) {
// return !!value.match(/^[ァ-ヶー ]*$/);
// })
// .required('氏名(カナ)は必須項目です。'),
});
おわりに
バリデーションチェックのライブラリはいくつかありますが、今回は react-hook-formとyupを選択して、組み合わせた内容を記述しました。
ありがとうございました。