はじめに
表題通り、ReactでFormikを実装します。
要件
・Validationチェックが実施
・必須項目が未入力の場合、送信ボタンが非活性
・送信ボタン押下後、POST通信が走る。
成果物
ディレクトリ
├── src
│ ├── App.tsx
│ ├── Form
│ │ ├── Field.tsx
│ │ ├── UserFormFileds.tsx
│ │ ├── const.ts
│ │ ├── hooks.ts
│ │ ├── index.tsx
│ │ ├── types.ts
│ │ └── validation.ts
│ ├── api
│ │ └── api.ts
│ ├── index.tsx
│ └── logo.svg
プログラム
App.tsx
import React from 'react';
import { UserForm } from './Form';
import { useMyFormik } from './Form/hooks';
import { UserFormFields } from './Form/UserFormFileds';
function App() {
// Form情報を取得
const formik = useMyFormik();
return (
<div>
<h1>Formikサンプル</h1>
<UserForm formik={formik}>
<UserFormFields formik={formik} />
</UserForm>
</div>
);
}
export default App;
src/Form/index.tsx
import { FormikProps } from 'formik';
import React from 'react';
import { UserFormValues } from './types';
export const UserForm: React.FC<UserFormProps> = (props) => {
const { formik, children } = props;
return (
<form onSubmit={formik.handleSubmit}>
{children}
<button type="submit" disabled={!formik.isValid}>
送信
</button>
</form>
);
};
type UserFormProps = {
formik: FormikProps<UserFormValues>; // UserFormValuesは入ってくる型を定義
children: React.ReactNode;
};
src/Form/UserFormFileds.tsx
import React from 'react';
import { FormikProps } from 'formik';
import { UserFormValues } from './types';
import { Field } from './Field';
type UserFormFieldsProps = {
formik: FormikProps<UserFormValues>;
};
export const UserFormFields: React.FC<UserFormFieldsProps> = ({ formik }) => {
return (
<div>
<Field formik={formik} fieldName="name" label="名前" type="text" />
<Field
formik={formik}
fieldName="email"
label="メールアドレス"
type="email"
/>
</div>
);
};
src/Form/Field.tsx
import React from 'react';
import { FormikProps } from 'formik';
import { UserFormValues } from './types';
type FieldProps = {
formik: FormikProps<UserFormValues>;
fieldName: keyof UserFormValues; // keyofでUserFormValuesのプロパティ名を取得
label: string;
type: string;
};
export const Field: React.FC<FieldProps> = ({
formik,
fieldName,
label,
type,
}) => {
const fieldError = formik.errors[fieldName];
const fieldValue = formik.values[fieldName];
const fieldTouched = formik.touched[fieldName];
return (
<div>
<label htmlFor={fieldName}>{label}</label>
<input
type={type}
id={fieldName as string}
name={fieldName as string}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={fieldValue}
/>
{fieldTouched && fieldError && <div>{fieldError}</div>}
</div>
);
};
src/Form/hooks.ts
import { useFormik } from 'formik';
import { useEffect } from 'react';
import { postApi } from '../api/api';
import { validationSchema } from './validation';
import { UserInitialValues } from './const';
export function useMyFormik() {
const formik = useFormik({
initialValues: UserInitialValues,
validationSchema,
onSubmit: async (values) => {
try {
const response = await postApi({
title: values.name, // 名前をタイトルとして使用
body: values.email, // メールアドレスを本文として使用
userId: 1, // ユーザーIDを適切に設定
});
// レスポンスをコンソールに出力
console.log('APIレスポンス:', response.data);
} catch (error) {
console.error('APIエラー:', error);
}
},
});
useEffect(() => {
formik.validateForm(); // フォームが最初にロードされたときにバリデーションを実行
}, []); // 空の依存リストを指定して一度だけ実行されるように
return formik;
}
src/Form/const.ts
export const UserInitialValues = {
name: '',
email: '',
};
src/Form/types.ts
export type UserFormValues = {
name: string;
email: string;
};
src/Form/validation.ts
import * as Yup from 'yup';
export const validationSchema = Yup.object({
name: Yup.string().required('名前は必須項目です'),
email: Yup.string()
.email('有効なメールアドレスを入力してください')
.required('メールアドレスは必須項目です'),
});
src/api/api.ts
import axios from "axios"
const apiUrl = "https://jsonplaceholder.typicode.com/posts";
export const postApi = async (payload:any) => {
const response = await axios.post(apiUrl, payload);
return response;
}
→Formikの難しいと感じる点は、useFormik
。onSubmitが結局いつ発火するのか。submitされた時に発火するのだが、フロント実装した事がないとonSubmitを追うけど、どこで使ってるの?ってところがわからない。上のサンプル実装だと以下のsubmit
された時に発火する。
<button type="submit" disabled={!formik.isValid}>
送信
</button>