LoginSignup
9
9

More than 3 years have passed since last update.

ReactでFormik + Yupを使う最低限(reactstrapを添えて)

Last updated at Posted at 2019-09-23

やりたいこと

ReactでFormikを利用する最低限のコードを作りたい(色々発展させる元としたい)。
とりあえず、以下のようのものができる。

スクリーンショット 2019-09-23 17.42.01.png

準備

作業場の作成と必要モジュールのインストール。

今回はcreate-react-appを使って雛形を作る。

create-react-app formikYup
cd formikYup

npm install --save formik
npm install --save yup

実装

App.js

App.jsで同じ階層にあるMyForm.jsを呼び出すようにしている(無駄なコードは削除)。

App.js
import React from 'react';
import MyForm from './MyForm';

function App() {
  return (
    <>
      <MyForm />
    </>
  );
}

export default App;

MyForm.js

いろいろな書き方があるが、いつもReact Nativeで書いているのと(個人的に)同じ書き方にしてみる。
バリデーションにはYupを利用することにする。

MyForm.js
import React from 'react';
import { Formik } from 'formik';
import * as Yup from 'yup';

export default class MyForm extends React.Component {
    render() {
        return (
            <div>
                <h2>My Form</h2>
                <Formik
                    initialValues={{ email: '', password: '' }}
                    onSubmit={(values, actions) => {
                        alert(JSON.stringify(values, null, 2));
                    }}
                    validationSchema={Yup.object().shape({
                        email: Yup.string().email('emailの形式がおかしいです。').required('emailは必須です。'),
                        password: Yup.string().required('パスワードは必須です。'),
                    })}
                >
                    {
                        ({ handleSubmit, handleChange, handleBlur, values, errors, touched }) => (
                            <form onSubmit={handleSubmit}>
                                <input
                                    type="email"
                                    name="email"
                                    onChange={handleChange}
                                    onBlur={handleBlur}
                                    value={values.email}
                                /><br />
                                {touched.email && errors.email ? <div>{errors.email}</div> : null}
                                <input
                                    type="password"
                                    name="password"
                                    onChange={handleChange}
                                    onBlur={handleBlur}
                                    value={values.password}
                                /><br />
                                {touched.password && errors.password ? <div>{errors.password}</div> : null}
                                <button type="submit">Submit</button>
                            </form>
                        )
                    }
                </Formik>
            </div>
        );
    }
}

応用:Bootstrap4を利用する

基本形?がわかったところでBootstrapを適用してみます。
下記のような完成形を目指します(エラーを起こさせているところ)。

スクリーンショット 2019-09-23 19.01.37.png

ReactでBootstrapを使うにはreactstrap等のモジュールを利用します。

インストール

reactstrapにはcssが含まれないため、bootstrapもインストールします。

npm install --save bootstrap
npm install --save reactstrap

App.js

ここでbootstrapのcssをimportしておきます。
で、別途、MyStrap.jsを作成してimportしています。
特に難しいところはありませんが、エラー表示のところにinvalidやら<FormFeedback></FormFeedback>などを利用しています。

Appjs
import React from 'react';
import MyForm from './MyForm';
import MyStrap from './MyStrap';
+import 'bootstrap/dist/css/bootstrap.min.css';

function App() {
  return (
    <>
      <MyStrap />
    </>
  );
}

export default App;

MyStrap.js

上記のMyForm.jsをベースにbootstrap化します。

MyStrap.js
import React from 'react';
import { Formik } from 'formik';
import * as Yup from 'yup';
import {
    Button,
    Form,
    FormGroup,
    Label,
    Input,
    FormFeedback,
} from 'reactstrap';

export default class MyStrap extends React.Component {
    render() {
        return (
            <div className="max-auto col-8">
                <h2>My Form</h2>
                <Formik
                    initialValues={{ email: '', password: '', gender: '', check: false }}
                    onSubmit={(values, actions) => {
                        alert(JSON.stringify(values, null, 2));
                    }}
                    validationSchema={Yup.object().shape({
                        email: Yup.string().email('emailの形式がおかしいです。').required('emailは必須です。'),
                        password: Yup.string().required('パスワードは必須です。'),
                        gender: Yup.string().oneOf(['male', 'female']).required('選択してください。'),
                        check: Yup.boolean().oneOf([true], '同意してください。'),
                    })}
                >
                    {
                        ({ handleSubmit, handleChange, handleBlur, values, errors, touched }) => (
                            <Form className="text-left" onSubmit={handleSubmit}>
                                {/* email */}
                                <FormGroup className="mb-2">
                                    <Label for="myEmail">Email</Label>
                                    <Input
                                        type="email"
                                        name="email"
                                        id="myEmail"
                                        onChange={handleChange}
                                        onBlur={handleBlur}
                                        value={values.email}
                                        invalid={touched.email && errors.email}
                                    />
                                    <FormFeedback>{errors.email}</FormFeedback>
                                    {/* {touched.email && errors.email ? <div>{errors.email}</div> : null} */}
                                </FormGroup>
                                {/* password */}
                                <FormGroup className="mb-2">
                                    <Label for="myPassword">Password</Label>
                                    <Input
                                        type="password"
                                        name="password"
                                        id="myPassword"
                                        onChange={handleChange}
                                        onBlur={handleBlur}
                                        value={values.password}
                                        invalid={touched.password && errors.password}
                                    />
                                    <FormFeedback>{errors.password}</FormFeedback>
                                    {/* {touched.password && errors.password ? <div>{errors.password}</div> : null} */}
                                </FormGroup>
                                {/* gender redio */}
                                <FormGroup className="mb-2" tag="fieldset">
                                    <p>性別</p>
                                    <FormGroup inline check>
                                        <Label check>
                                            <Input type="radio" name="gender" value="male" onChange={handleChange} />male
                                    </Label>
                                    </FormGroup>
                                    <FormGroup inline check>
                                        <Label check>
                                            <Input type="radio" name="gender" value="female" onChange={handleChange} />female
                                    </Label>
                                    </FormGroup>
                                    <span className="ml-3 text-danger" style={{ fontSize: '0.8rem' }}>
                                        {touched.gender && errors.gender ? <span>{errors.gender}</span> : null}
                                    </span>
                                </FormGroup>
                                {/* checkbox */}
                                <FormGroup check className="mb-2" style={{ marginTop: 30 }}>
                                    <Input type="checkbox" name="check" id="myCheck" onChange={handleChange} />
                                    <Label for="myCheck" check>
                                        同意する
                                    </Label>
                                    <span className="ml-3 text-danger" style={{ fontSize: '0.8rem' }}>
                                        {touched.check && errors.check ? <span>{errors.check}</span> : null}
                                    </span>
                                </FormGroup>
                                {/* Button */}
                                <div style={{ marginTop: 30 }}>
                                    <Button type="submit" color="primary">Submit</Button>
                                </div>

                            </Form>
                        )
                    }
                </Formik>
            </div>
        );
    }
}

 おまけ

上記はreactstrapを利用していますが、react-bootstrapを利用したパータンも下記に追記しておきます。
利用のためには、

yarn add react-bootstrap bootstrap

としておく必要があります。詳しくは本家サイトをみればいいでしょう。

import React from 'react';
import { Formik } from 'formik';
import * as Yup from 'yup';
import { Form, Button, FormGroup, } from 'react-bootstrap';

export default class SimpleForm extends React.Component {
    render() {
        return (
            <div className="container" style={{ marginTop: 30 }}>
                <div className="mx-auto col-8">
                    <h2>SimpleForm</h2>
                    <Formik
                        initialValues={{ email: '', password: '', area: '', note: '', gender: '', agree: false }}
                        onSubmit={(values) => alert(JSON.stringify(values))}
                        validationSchema={Yup.object().shape({
                            email: Yup.string().email().required(),
                            password: Yup.string().required(),
                            area: Yup.string().oneOf(['関東', '関西', 'その他'], '選択してください。').required(),
                            note: Yup.string().required(),
                            gender: Yup.string().oneOf(['male', 'female']).required('どちらかを選択してください。'),
                            agree: Yup.boolean().oneOf([true], '同意してください。'),
                        })}
                    >
                        {
                            ({ handleSubmit, handleChange, handleBlur, values, errors, touched }) => (
                                <Form onSubmit={handleSubmit}>
                                    <Form.Group>
                                        <Form.Label>Email</Form.Label>
                                        <Form.Control
                                            type="email"
                                            name="email"
                                            onChange={handleChange}
                                            onBlur={handleBlur}
                                            value={values.email}
                                            isInvalid={!!(touched.email && errors.email)}
                                        />
                                        <Form.Control.Feedback type="invalid">
                                            {errors.email}
                                        </Form.Control.Feedback>
                                    </Form.Group>
                                    <Form.Group>
                                        <Form.Label>Password</Form.Label>
                                        <Form.Control
                                            type="password"
                                            name="password"
                                            onChange={handleChange}
                                            onBlur={handleBlur}
                                            value={values.password}
                                            isInvalid={!!(touched.password && errors.password)}
                                        />
                                        <Form.Control.Feedback type="invalid">
                                            {errors.password}
                                        </Form.Control.Feedback>
                                    </Form.Group>

                                    <Form.Group>
                                        <Form.Label>お住まいのエリア</Form.Label>
                                        <Form.Control
                                            as="select"
                                            name="area"
                                            onChange={handleChange}
                                            onBlur={handleBlur}
                                            value={values.area}
                                            isInvalid={!!(touched.area && errors.area)}
                                        >
                                            <option>選択してください</option>
                                            <option>関東</option>
                                            <option>関西</option>
                                            <option>その他</option>
                                        </Form.Control>
                                        <Form.Control.Feedback type="invalid">
                                            {errors.area}
                                        </Form.Control.Feedback>
                                    </Form.Group>

                                    <Form.Group>
                                        <Form.Label>お問合せ内容</Form.Label>
                                        <Form.Control
                                            as="textarea"
                                            rows="5"
                                            name="note"
                                            onChange={handleChange}
                                            onBlur={handleBlur}
                                            value={values.note}
                                            isInvalid={!!(touched.note && errors.note)}
                                        />
                                        <Form.Control.Feedback type="invalid">
                                            {errors.note}
                                        </Form.Control.Feedback>
                                    </Form.Group>

                                    <Form.Group>
                                        <Form.Label>性別</Form.Label>
                                        <Form.Group>
                                            <Form.Check
                                                type="radio"
                                                label=""
                                                name="gender"
                                                value="male"
                                                inline
                                                onChange={handleChange}
                                                isInvalid={!!errors.gender}
                                            />
                                            <Form.Check
                                                type="radio"
                                                label=""
                                                name="gender"
                                                value="female"
                                                inline
                                                onChange={handleChange}
                                                isInvalid={!!errors.gender}
                                            />
                                        </Form.Group>
                                        <span className="text-danger" style={{ fontSize: '0.8rem' }}>
                                            {errors.gender}
                                        </span>
                                    </Form.Group>

                                    <Form.Group>
                                        <Form.Label>同意</Form.Label>
                                        <Form.Group>
                                            <Form.Check
                                                type="checkbox"
                                                label="同意する"
                                                name="agree"
                                                value="true"
                                                onChange={handleChange}
                                                isInvalid={!!errors.agree}
                                                feedback={errors.agree}
                                            />
                                        </Form.Group>
                                        {/* <span className="text-danger" style={{ fontSize: '0.8rem' }}>
                                        {errors.agree}
                                    </span> */}
                                    </Form.Group>

                                    {/* button */}
                                    <Button variant="primary" type="submit">Submit</Button>
                                </Form>
                            )
                        }
                    </Formik>
                </div>
            </div>
        );
    }
}

参考

9
9
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
9
9