32
25

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 3 years have passed since last update.

React Formikの入門編

Last updated at Posted at 2020-08-16

react-formik

YouTube チャンネル CodeEvolutionの「React Formik」を参考に学習しましたので共有します。

set up

terminal
$ npm i formik

useFormik を使って form 実装 Basic 編

useFormik で実装すること

  • form の各 value の値を管理
  • handling submit
  • validate
formのHTML
<div>
  <form>
    <label htmlFor="name">Name</label>
    <input type="text" id="name" name="name" />

    <label htmlFor="email">E-mail</label>
    <input type="email" id="email" name="email" />

    <label htmlFor="channel">Channel</label>
    <input type="text" id="channel" name="channel" />

    <button>Submit</button>
  </form>
</div>

form の各 value の値を管理

  • useFormik 関数を変数(formik)で管理
  • formik.values で各要素の value を管理
  • useFormik 関数の object にinitialValuesを設定して、各 form 要素の初期値を管理
  • initialValues の key 名は form 要素のnameの値
  • onChage 属性に useFormik の APIhandleChangeを指定。onChange={formik.handleChange}formik.valuesで設定した name を key としたデータが入る
  • value 属性に useFormik の APIvaluesを指定。value={formik.values.{name名}}formik.valuesで設定した name のデータが表示される
import { useFormik } from 'formik';

const formik = useFormik({
  initialValues: {
    name: '',
    email: '',
    channel: '',
  },
});
<input
  type="text"
  id="name"
  name="name"
  onChange={formik.handleChange}
  value={formik.values.name}
/>
Sample.js
import React from 'react';
import { useFormik } from 'formik';

function YoutubeForm() {
  const formik = useFormik({
    initialValues: {
      name: '',
      email: '',
      channel: '',
    },
  });

  console.log('form valuse', formik.values);

  return (
    <div>
      <form>
        <label htmlFor="name">Name</label>
        <input
          type="text"
          id="name"
          name="name"
          onChange={formik.handleChange}
          value={formik.values.name}
        />

        <label htmlFor="email">E-mail</label>
        <input
          type="email"
          id="email"
          name="email"
          onChange={formik.handleChange}
          value={formik.values.email}
        />

        <label htmlFor="channel">Channel</label>
        <input
          type="text"
          id="channel"
          name="channel"
          onChange={formik.handleChange}
          value={formik.values.channel}
        />

        <button>Submit</button>
      </form>
    </div>
  );
}

export default YoutubeForm;

submit ボタンを押下して form data を取得

  • form タグのonSubmit属性に useFormik の APIhandleSubmitを指定。onSubmit={formik.handleSubmit}
  • button タグの type をsubmitにする
  • useFormik関数の object にonSubmitメソッドを記述して form の各要素の value を取得
const formik = useFormik({
  onSubmit: (values) => {
    console.log('form data', values);
  },
});
<form onSubmit={formik.handleSubmit}>
<button type="submit">Submit</button>
Sample.js
import React from 'react';
import { useFormik } from 'formik';

function YoutubeForm() {
  const formik = useFormik({
    initialValues: {
      name: '',
      email: '',
      channel: '',
    },
    onSubmit: (values) => {
      console.log('form data', values);
    },
  });

  return (
    <div>
      <form onSubmit={formik.handleSubmit}>
        <label htmlFor="name">Name</label>
        <input
          type="text"
          id="name"
          name="name"
          onChange={formik.handleChange}
          value={formik.values.name}
        />

        <label htmlFor="email">E-mail</label>
        <input
          type="email"
          id="email"
          name="email"
          onChange={formik.handleChange}
          value={formik.values.email}
        />

        <label htmlFor="channel">Channel</label>
        <input
          type="text"
          id="channel"
          name="channel"
          onChange={formik.handleChange}
          value={formik.values.channel}
        />

        <button type="submit">Submit</button>
      </form>
    </div>
  );
}

export default YoutubeForm;

validate 実装

  • useFormik 関数に validate メソッドを指定
  • validate メソッドにはerrorsを戻り値とする
  • validate メソッドの引数valuesには各要素の name の値を key とした value が入る
  • formik.errorsで各要素のエラーメッセージを取得
const formik = useFormik({
  validate: (values) => {
    let errors = {};

    if (!values.name) {
      errors.name = 'Name is Required';
    }

    if (!values.email) {
      errors.email = 'Email is Required';
    } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
      errors.email = 'Invalid email format';
    }

    if (!values.channel) {
      errors.channel = 'Channel is Required';
    }

    return errors;
  }
});
{formik.errors.name ? (
  <div className="error">{formik.errors.name}</div>
) : null}
Sample.js
import React from 'react';
import { useFormik } from 'formik';

const initialValues = {
  name: '',
  email: '',
  channel: '',
};

const onSubmit = (values) => {
  console.log('form data', values);
};

const validate = (values) => {
  let errors = {};

  if (!values.name) {
    errors.name = 'Name is Required';
  }

  if (!values.email) {
    errors.email = 'Email is Required';
  } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
    errors.email = 'Invalid email format';
  }

  if (!values.channel) {
    errors.channel = 'Channel is Required';
  }

  return errors;
};

function YoutubeForm() {
  const formik = useFormik({
    initialValues,
    onSubmit,
    validate,
  });

  return (
    <div>
      <form onSubmit={formik.handleSubmit}>
        <div className="form-control">
          <label htmlFor="name">Name</label>
          <input
            type="text"
            id="name"
            name="name"
            onChange={formik.handleChange}
            value={formik.values.name}
          />
          {formik.errors.name ? (
            <div className="error">{formik.errors.name}</div>
          ) : null}
        </div>

        <div className="form-control">
          <label htmlFor="email">E-mail</label>
          <input
            type="email"
            id="email"
            name="email"
            onChange={formik.handleChange}
            value={formik.values.email}
          />
          {formik.errors.email ? (
            <div className="error">{formik.errors.email}</div>
          ) : null}
        </div>

        <div className="form-control">
          <label htmlFor="channel">Channel</label>
          <input
            type="text"
            id="channel"
            name="channel"
            onChange={formik.handleChange}
            value={formik.values.channel}
          />
          {formik.errors.channel ? (
            <div className="error">{formik.errors.channel}</div>
          ) : null}
        </div>

        <button type="submit">Submit</button>
      </form>
    </div>
  );
}

export default YoutubeForm;

validate 選択項目のみエラーメッセージを表示

  • ユーザーが touch した項目のみ validate を検知
  • handleBlur したときにエラーメッセージ表示
<input
  onBlur={formik.handleBlur}
/>
{formik.touched.name && formik.errors.name ? (
  <div className="error">{formik.errors.name}</div>
) : null}
Sample.js
import React from 'react';
import { useFormik } from 'formik';

const initialValues = {
  name: '',
  email: '',
  channel: '',
};

const onSubmit = (values) => {
  console.log('form data', values);
};

const validate = (values) => {
  let errors = {};

  if (!values.name) {
    errors.name = 'Name is Required';
  }

  if (!values.email) {
    errors.email = 'Email is Required';
  } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
    errors.email = 'Invalid email format';
  }

  if (!values.channel) {
    errors.channel = 'Channel is Required';
  }

  return errors;
};

function YoutubeForm() {
  const formik = useFormik({
    initialValues,
    onSubmit,
    validate,
  });

  return (
    <div>
      <form onSubmit={formik.handleSubmit}>
        <div className="form-control">
          <label htmlFor="name">Name</label>
          <input
            type="text"
            id="name"
            name="name"
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.name}
          />
          {formik.touched.name && formik.errors.name ? (
            <div className="error">{formik.errors.name}</div>
          ) : null}
        </div>

        <div className="form-control">
          <label htmlFor="email">E-mail</label>
          <input
            type="email"
            id="email"
            name="email"
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.email}
          />
          {formik.touched.email && formik.errors.email ? (
            <div className="error">{formik.errors.email}</div>
          ) : null}
        </div>

        <div className="form-control">
          <label htmlFor="channel">Channel</label>
          <input
            type="text"
            id="channel"
            name="channel"
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.channel}
          />
          {formik.touched.channel && formik.errors.channel ? (
            <div className="error">{formik.errors.channel}</div>
          ) : null}
        </div>

        <button type="submit">Submit</button>
      </form>
    </div>
  );
}

export default YoutubeForm;

useFormik を使って form 実装 Advanced 編

yup を install

  • formik と連携してバリデーションチェックをする package
  • Yup.object にvalidation schemaを定義
  • useFormik 関数の object に指定
$ npm i yup
import * as Yup from 'yup';

const validationSchema = Yup.object({
  name: Yup.string().required('Required'),
  email: Yup.string().email('Invalid email format').required('Required'),
  channel: Yup.string().required('Required'),
});
const formik = useFormik({
  initialValues,
  onSubmit,
  validationSchema,
});
Sample.js
import * as Yup from 'yup';

import React from 'react';
import { useFormik } from 'formik';

const initialValues = {
  name: '',
  email: '',
  channel: '',
};

const onSubmit = (values) => {
  console.log('form data', values);
};

const validationSchema = Yup.object({
  name: Yup.string().required('Required'),
  email: Yup.string().email('Invalid email format').required('Required'),
  channel: Yup.string().required('Required'),
});

function YoutubeForm() {
  const formik = useFormik({
    initialValues,
    onSubmit,
    validationSchema,
  });

  return (
    <div>
      <form onSubmit={formik.handleSubmit}>
        <div className="form-control">
          <label htmlFor="name">Name</label>
          <input
            type="text"
            id="name"
            name="name"
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.name}
          />
          {formik.touched.name && formik.errors.name ? (
            <div className="error">{formik.errors.name}</div>
          ) : null}
        </div>

        <div className="form-control">
          <label htmlFor="email">E-mail</label>
          <input
            type="email"
            id="email"
            name="email"
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.email}
          />
          {formik.touched.email && formik.errors.email ? (
            <div className="error">{formik.errors.email}</div>
          ) : null}
        </div>

        <div className="form-control">
          <label htmlFor="channel">Channel</label>
          <input
            type="text"
            id="channel"
            name="channel"
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.channel}
          />
          {formik.touched.channel && formik.errors.channel ? (
            <div className="error">{formik.errors.channel}</div>
          ) : null}
        </div>

        <button type="submit">Submit</button>
      </form>
    </div>
  );
}

export default YoutubeForm;

formik.getFieldProps({name 属性の値})で refactor

  • onChange属性onBlur属性value属性の指定を getFieldProps メソッドでリファクタリングする
  • name 属性で指定した値を引数に設定
  • スプレッド構文で展開
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.name}



{...formik.getFieldProps('name')}
Sample.js
import * as Yup from 'yup';

import React from 'react';
import { useFormik } from 'formik';

const initialValues = {
  name: '',
  email: '',
  channel: '',
};

const onSubmit = (values) => {
  console.log('form data', values);
};

const validationSchema = Yup.object({
  name: Yup.string().required('Required'),
  email: Yup.string().email('Invalid email format').required('Required'),
  channel: Yup.string().required('Required'),
});

function YoutubeForm() {
  const formik = useFormik({
    initialValues,
    onSubmit,
    validationSchema,
  });

  return (
    <div>
      <form onSubmit={formik.handleSubmit}>
        <div className="form-control">
          <label htmlFor="name">Name</label>
          <input
            type="text"
            id="name"
            name="name"
            {...formik.getFieldProps('name')}
          />
          {formik.touched.name && formik.errors.name ? (
            <div className="error">{formik.errors.name}</div>
          ) : null}
        </div>

        <div className="form-control">
          <label htmlFor="email">E-mail</label>
          <input
            type="email"
            id="email"
            name="email"
            {...formik.getFieldProps('email')}
          />
          {formik.touched.email && formik.errors.email ? (
            <div className="error">{formik.errors.email}</div>
          ) : null}
        </div>

        <div className="form-control">
          <label htmlFor="channel">Channel</label>
          <input
            type="text"
            id="channel"
            name="channel"
            {...formik.getFieldProps('channel')}
          />
          {formik.touched.channel && formik.errors.channel ? (
            <div className="error">{formik.errors.channel}</div>
          ) : null}
        </div>

        <button type="submit">Submit</button>
      </form>
    </div>
  );
}

export default YoutubeForm;

Formik コンポーネントで全体をラップ

  • formik が提供している Formik コンポーネントで form タグを wrap
  • Formikコンポーネントの propsinitialValuesvalidationSchemaonSubmitにそれぞれの変数を指定
import { Formik } from 'formik';
<Formik
  initialValues={initialValues}
  validationSchema={validationSchema}
  onSubmit={onSubmit}
>

form タグを Form コンポーネントに変更

  • formik が提供している Form コンポーネントを form タグと変更
  • form タグで指定した onSubmit 属性を削除
import { Form } from 'formik';
<form onSubmit={formik.handleSubmit}>

<Form>

input タグを Field コンポーネントに変更

  • formik が提供している Field コンポーネントを input タグと変更
  • {...formik.getFieldProps()}を削除
import { Field } from 'formik';
<input type="text" id="name" name="name" {...formik.getFieldProps('name')} />
↓
<Field type="text" id="name" name="name" />

ErrorMessage コンポーネントでエラーメッセージ表示

  • formik が提供している ErrorMessage コンポーネントでエラーメッセージ表示
import { ErrorMessage } from 'formik';
{formik.touched.name && formik.errors.name ? (
  <div className="error">{formik.errors.name}</div>
) : null}

<ErrorMessage name="name" />
Sample.js
import * as Yup from 'yup';

import { ErrorMessage, Field, Form, Formik } from 'formik';

import React from 'react';

const initialValues = {
  name: '',
  email: '',
  channel: '',
};

const onSubmit = (values) => {
  console.log('form data', values);
};

const validationSchema = Yup.object({
  name: Yup.string().required('Required'),
  email: Yup.string().email('Invalid email format').required('Required'),
  channel: Yup.string().required('Required'),
});

function YoutubeForm() {
  return (
    <Formik
      initialValues={initialValues}
      validationSchema={validationSchema}
      onSubmit={onSubmit}
    >
      <Form>
        <div className="form-control">
          <label htmlFor="name">Name</label>
          <Field type="text" id="name" name="name" />
          <ErrorMessage name="name" />
        </div>

        <div className="form-control">
          <label htmlFor="email">E-mail</label>
          <Field type="email" id="email" name="email" />
          <ErrorMessage name="email" />
        </div>

        <div className="form-control">
          <label htmlFor="channel">Channel</label>
          <Field type="text" id="channel" name="channel" />
          <ErrorMessage name="channel" />
        </div>

        <button type="submit">Submit</button>
      </Form>
    </Formik>
  );
}

export default YoutubeForm;

Field コンポーネントについて

  • placeholderprops で placeholder を入力できる
  • asprops で textarea、select タグを設定できる
  • fieldコンポーネントの children に関数が書ける。その関数の引数にfieldformmetaが設定される
<Field placeholder="YouTube channel name" />
<Field as="textarea" id="comments" name="comments" />
<Field name="address">
  {({ field, form, meta }) => {
    return (
      <div>
        <input type="text" {...field} />
        {meta.touched && meta.error ? <div>{meta.error}</div> : null}
      </div>
    );
  }}
</Field>

ErrorMessage コンポーネントについて

  • ErrorMessage コンポーネントのcomponentprops に作成した component を指定できる
  • そのとき作成した component のprops.childrenに error message が表示される
  • ErrorMessage コンポーネントの children に関数を設定できる
  • その関数の引数には error message が設定される
function TextError(props) {
  return <div className="error">{props.children}</div>;
}

<ErrorMessage name="name" component={TextError} />
<ErrorMessage name="email">
  {(msg) => <div className="error">{msg}</div>}
</ErrorMessage>

value に nest された object を 指定

  • initialValuesで nest された object を指定
  • Fieldコンポーネントの name 属性で object の key を指定
const initialValues = {
  social: {
    facebook: '',
    twitter: '',
  },
};
<Field type="text" id="twitter" name="social.twitter" />

value に配列を指定

  • initialValuesで value に配列を指定
  • Fieldコンポーネントの name 属性で 配列の key と配列番号 を指定
const initialValues = {
  phoneNumbers: ['', ''],
};
<Field type="text" id="primaryPh" name="phoneNumbers[0]" />
<Field type="text" id="secondaryPh" name="phoneNumbers[1]" />

Field Array コンポーネントで動的に input タグを増減させる

  • formik が提供しているFieldArrayコンポーネントを使用
  • initialValuesで配列を value とした key を設定
  • FieldArrayコンポーネントの name 属性にinitialValuesで設定した key を指定
  • FieldArrayコンポーネントの children に関数を設定
  • 関数の引数にはpushremoveformなどの API が設定されている
    • form には value の key があり、initialValuesで設定した key が管理されている
    • その key を map させて、Fieldコンポーネントと button を配置させる
    • Fieldコンポーネントの name 属性はinitialValuesで設定した key と map の引数(index)を結合させる
    • map の引数(index)を使用してremove(index)で input タグの削除を行う
    • 先頭の input タグは削除しないように設定する
    • button タグの onClick 属性にpush('')を設定で input タグを増やす
import { FieldArray } from 'formik';
const initialValues = {
  phNumbers: [''],
};
<FieldArray name="phNumbers">
  {(fieldArrayProps) => {
    const { push, remove, form } = fieldArrayProps;
    const {
      values: { phNumbers },
    } = form;
    return (
      <div>
        {phNumbers.map((phNumber, index) => (
          <div key={index}>
            <Field name={`phNumbers[${index}]`} />
            {index > 0 && (
              <button type="button" onClick={() => remove(index)}>
                -
              </button>
            )}
          </div>
        ))}
        <button type="button" onClick={() => push('')}>
          +
        </button>
      </div>
    );
  }}
</FieldArray>

FastField コンポーネントでレンダリングを制御

  • Fieldコンポーネントを操作したとき、他のFieldコンポーネントもレンダリングされる
  • formik で提供されているFastField コンポーネントを使用すると、そのコンポーネントのみレンダリングされる
  • 1 画面に 30 以上のFieldコンポーネントがあある場合にFastFieldの使用でパフォーマンスが良くなる
import { FastField } from 'formik';
<FastField name="address">
  {({ field, form, meta }) => {
    console.log('Field render');
    return (
      <div>
        <input type="text" {...field} />
        {meta.touched && meta.error ? <div>{meta.error}</div> : null}
      </div>
    );
  }}
</FastField>

validation が走るタイミングを制御

  • デフォルトでは form の各項目をonChangeonBlurしたタイミングで validation が走る
  • Formikコンポーネントの props でvalidateOnChangevalidateOnBlurfalseにすると validation が走らないようになる
<Formik
  validateOnChange={false}
  validateOnBlur={false}
>

Field コンポーネントで validation を定義

  • validationSchemaで validation を制御するのではなく、Fieldコンポーネントのvalidate props で validation を制御
  • vilidateprops には関数が指定でき、引数にはvalueが入る
  • formik が提供しているErrorMessageコンポーネントでエラーメッセージを表示
const initialValues = {
  comments: '',
};

const validateComments = (value) => {
  let error;
  if (!value) {
    error = 'Required';
  }
  return error;
};
<Field validate={validateComments} />
<ErrorMessage name="comments" />

trigger validation

  • Formikコンポーネントの children に関数を設定できて、その関数の引数にはヘルパーメソッドが定義されている
  • formik.validateField({name属性の値})formik.setFieldTouched({name属性の値})で単一の fileld の値取得と操作ができる
  • formik.validateForm()formik.setTouched({ name: true })で validation を設定した全ての値取得と操作ができる
<Formik
  initialValues={initialValues}
  validationSchema={validationSchema}
  onSubmit={onSubmit}
>
  {(formik) => {
    return (
      <Form>
      .
      .
      .
      </Form>
    )
  }}
</Formik>
<button
  type="button"
  onClick={() => formik.validateField('comments')}
>
  Validate comments
</button>
<button
  type="button"
  onClick={() => formik.setFieldTouched('comments')}
>
  Visit comments
</button>
<button type="button" onClick={() => formik.validateForm()}>
  Validate all
</button>
<button
  type="button"
  onClick={() =>
    formik.setTouched({
      name: true,
      email: true,
      channel: true,
      comments: true,
    })
  }
>
  Visit all
</button>

submit ボタンを disabled で制御

  • formik.isValidで validation エラーの有無を boolean で取得。trueの場合はエラーなし
    • formik.isValidのみで disabled を制御すると page ロード時はエラーがないのでボタンが活性化される
  • formik.dirtyinitialValuesと値が同じかをチェック
    • required の値がinitialValues時に入ってる場合、formik.dirtyで値と同じではないとfalseになる。よって disabled は制御できない
  • formik.isSubmittingで submit ボタンが押されたかを判定(trueの場合は押下)。この判定により API にデータを POST している非同期処理中はfalseに設定して、submit ボタンを非活性化にする
    • onSubmit関数の引数submitPropsのメソッドsetSubmittingformik.isSubmittingを制御できる
const onSubmit = (values, submitProps) => {
  submitProps.setSubmitting(false);
};
<button
  type="submit"
  disabled={!formik.isValid || formik.isSubmitting}
>

この記述でページ初期画面はボタンが活性化になっているが、押下するとエラーメッセージが表示され、onSubmit 関数が処理されない

load data で initialValues の値を変更する

  • mock としてinitialValuesと同じ schema のsavedValuesを用意
  • button を押下したときに useState でsavedValuesで設定した値に変更
  • Formikの propsinitialValuessavedValuesまたはinitialValuesの値になるようにする
  • Formikの props でenableReinitializeinitialValuesが変更可能に
const savedValues = {
  name: 'Vishwas',
  email: 'v@example.com',
  channel: 'codevolution',
  comments: 'Welcome to Formik',
  address: '221B Baker Street',
  social: {
    facebook: '',
    twitter: '',
  },
  phoneNumbers: ['', ''],
  phNumbers: [''],
};
const [formValues, setFormValues] = useState(null);
<button type="button" onClick={() => setFormValues(savedValues)}>
  Load saved data
</button>
<Formik
  initialValues={formValues || initialValues}
  enableReinitialize
>

Form の値を reset させる

  • button を押下して reset させるにはtype="reset"を設定する
  • submit ボタンを押下した後に reset させるにはonSubmit関数の引数submitPropsのメソッドを使用submitProps.resetForm()
<button type='reset'>Reset</button>
const onSubmit = (values, submitProps) => {
  submitProps.resetForm();
};

Sample.jsの最終形

Sample.js
import * as Yup from 'yup';

import {
  ErrorMessage,
  FastField,
  Field,
  FieldArray,
  Form,
  Formik,
} from 'formik';
import React, { useState } from 'react';

import TextError from './TextError';

const initialValues = {
  name: '',
  email: '',
  channel: '',
  comments: '',
  address: '',
  social: {
    facebook: '',
    twitter: '',
  },
  phoneNumbers: ['', ''],
  phNumbers: [''],
};

const savedValues = {
  name: 'Vishwas',
  email: 'v@example.com',
  channel: 'codevolution',
  comments: 'Welcome to Formik',
  address: '221B Baker Street',
  social: {
    facebook: '',
    twitter: '',
  },
  phoneNumbers: ['', ''],
  phNumbers: [''],
};

const onSubmit = (values, submitProps) => {
  console.log('form data', values);
  console.log('submitProps', submitProps);
  submitProps.setSubmitting(false);
  submitProps.resetForm();
};

const validationSchema = Yup.object({
  name: Yup.string().required('Required'),
  email: Yup.string().email('Invalid email format').required('Required'),
  channel: Yup.string().required('Required'),
});

const validateComments = (value) => {
  let error;
  if (!value) {
    error = 'Required';
  }
  return error;
};

function YoutubeForm() {
  const [formValues, setFormValues] = useState(null);
  return (
    <Formik
      initialValues={formValues || initialValues}
      validationSchema={validationSchema}
      onSubmit={onSubmit}
      enableReinitialize
      // validateOnMount
      // validateOnChange={false}
      // validateOnBlur={false}
    >
      {(formik) => {
        console.log('Formik props', formik);
        return (
          <Form>
            <div className="form-control">
              <label htmlFor="name">Name</label>
              <Field type="text" id="name" name="name" />
              <ErrorMessage name="name" component={TextError} />
            </div>

            <div className="form-control">
              <label htmlFor="email">E-mail</label>
              <Field type="email" id="email" name="email" />
              <ErrorMessage name="email">
                {(error) => <div className="error">{error}</div>}
              </ErrorMessage>
            </div>

            <div className="form-control">
              <label htmlFor="channel">Channel</label>
              <Field
                type="text"
                id="channel"
                name="channel"
                placeholder="YouTube channel name"
              />
              <ErrorMessage name="channel" />
            </div>

            <div className="form-control">
              <label htmlFor="comments">Comments</label>
              <Field
                as="textarea"
                id="comments"
                name="comments"
                validate={validateComments}
              />
              <ErrorMessage name="comments" component={TextError} />
            </div>

            <div className="form-control">
              <label htmlFor="address">Address</label>
              <FastField name="address">
                {({ field, form, meta }) => {
                  return (
                    <div>
                      <input type="text" {...field} />
                      {meta.touched && meta.error ? (
                        <div>{meta.error}</div>
                      ) : null}
                    </div>
                  );
                }}
              </FastField>
            </div>

            <div className="form-control">
              <label htmlFor="facebook">Facebook profile</label>
              <Field type="text" id="facebook" name="social.facebook" />
            </div>

            <div className="form-control">
              <label htmlFor="twitter">Twitter profile</label>
              <Field type="text" id="twitter" name="social.twitter" />
            </div>

            <div className="form-control">
              <label htmlFor="primaryPh">Primary phone number</label>
              <Field type="text" id="primaryPh" name="phoneNumbers[0]" />
            </div>

            <div className="form-control">
              <label htmlFor="secondaryPh">Secondary phone number</label>
              <Field type="text" id="secondaryPh" name="phoneNumbers[1]" />
            </div>

            <div className="form-control">
              <label>List of phone numbers</label>
              <FieldArray name="phNumbers">
                {(fieldArrayProps) => {
                  const { push, remove, form } = fieldArrayProps;
                  const {
                    values: { phNumbers },
                  } = form;
                  return (
                    <div>
                      {phNumbers.map((phNumber, index) => (
                        <div key={index}>
                          <Field name={`phNumbers[${index}]`} />
                          {index > 0 && (
                            <button type="button" onClick={() => remove(index)}>
                              -
                            </button>
                          )}
                        </div>
                      ))}
                      <button type="button" onClick={() => push('')}>
                        +
                      </button>
                    </div>
                  );
                }}
              </FieldArray>
            </div>
            <button type="button" onClick={() => setFormValues(savedValues)}>
              Load saved data
            </button>
            <button type="reset">Reset</button>
            <button
              type="submit"
              disabled={!formik.isValid || formik.isSubmitting}
            >
              Submit
            </button>
          </Form>
        );
      }}
    </Formik>
  );
}

export default YoutubeForm;
32
25
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
32
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?