0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

はじめに

表題通り、ReactでFormikを実装します。

要件

・Validationチェックが実施
・必須項目が未入力の場合、送信ボタンが非活性
・送信ボタン押下後、POST通信が走る。

成果物

スクリーンショット 2023-11-01 23.17.52.png

ディレクトリ
├── 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>
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?