React のフォームに Fomik を使って yup でバリデーションした React Select を作る (React Bootstrap 使用)
2022/07/14
バリデーション
- 【2022年】 React Hook FormでValidationライブラリはどれにするか?
- Reactのフォーム、バリデーションライブラリの比較
- Reactで使えるバリデーションライブラリを紹介! - bagelee(ベーグリー)
zod は TypeScript 前提なので yup にした。
yup
URL
url が strict 過ぎるので。ちなみにこの正規表現だと https://localhost/ のようなパターンも引っかかってしまうので
/((https?):\/\/)?(www.)?[a-z0-9]+((\.[a-z]{2,}){1,3})*(#?\/?[a-zA-Z0-9#]+)*\/?(\?[a-zA-Z0-9-_]+=[a-zA-Z0-9-%]+&?)?$/
こうした。
Formik
- React-Bootstrap · React-Bootstrap Documentation
- React Hook Form と Yup でとりあえずのフォーム
- ReactHooksでBMI計算フォームを作成する(bootstrap/formik/yup使用) - フリーランス 技術調査ブログ
どうやら React では普通にフォームは作らず、 Formik 等の力を借りて管理するらしい。幸い、 React Bootstrap + Formik + yup の組み合わせが React Bootstrap 公式ドキュメントにあるのでこれをベースに。
React Select
- reactjs - React-Select with Formik Reset/Clear button - Stack Overflow
- Use react-select with Formik · GitHub
- formikのonChangeとは別に動作を実行したいとき
React Select + Formik パターン。まだ TypeScript に着手できていないのと、今回は Clearable かつ Searchable かつ Multi にしたかったのでサンプルがなく苦戦。
SelectField
import React from 'react';
import CreatableSelect from 'react-select/creatable';
const SelectField = ({
options,
field,
form,
}) => {
return (
<CreatableSelect
isClearable
isSearchable
isMulti
options={options}
id={field.name}
name={field.name}
value={field.value}
onChange={(option) => {
return form.setFieldValue(field.name, option);
}}
onBlur={field.onBlur}
/>
)
};
export default SelectField;
Form
import React, { useState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Form } from 'react-bootstrap';
import SelectField from './SelectField';
import { Formik, Field } from 'formik';
import { object, string, array } from 'yup';
const schema = object({
categories: array().of(string()).ensure(),
tags: array().of(string()).ensure()
});
const ComponentForm = () => {
return (
<>
<Formik
validationSchema={schema}
onSubmit={console.log}
initialValues={{
categories: categoryArray,
tags: tagArray,
}}
>
{({
handleSubmit,
handleChange,
handleBlur,
values,
touched,
isValid,
errors,
}) => {
return (
<Form noValidate onSubmit={handleSubmit}>
<Form.Group className="mb-3" controlId="categories">
<Form.Label>
<FontAwesomeIcon className="me-2" icon={faFolderTree} />
カテゴリ
</Form.Label>
<Field
name="categories"
value={elem.categories}
options={categoryDatas}
component={SelectField}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="tags">
<Form.Label>
<FontAwesomeIcon className="me-2" icon={faTags} />
タグ
</Form.Label>
<Field
name="tags"
value={elem.tags}
options={tagDatas}
component={SelectField}
/>
</Form.Group>
<Button variant="primary" type="submit">
<FontAwesomeIcon className="me-2" icon={faSave} />
保存
</Button>
</Form>
)}}
</Formik>
</>
);
};
export default ComponentForm;
こんな感じで予期した挙動にすることができた。