LoginSignup
1
1

More than 3 years have passed since last update.

Formikでreact-bootstrapを使いたい

Last updated at Posted at 2020-03-08

はじめに

先日react-redux-fromからFormikに切り換えたのですが、普段使いのUI Frameworkはreact-bootstrapなんです。Formikの公式を見ると、未対応じゃないですかreactstrapっていつの間にかBootstrap4に対応していたんですね…。知らなかった…。ドキュメントとか不親切だからreact-bootstrapの方が良いと思うんですけどね。

仕方がないので

自分でコンポーネントを作ることにしました。
希望する機能としては以下の通り。

  • Input Groupに対応
  • <Field name="name" component={Text} />よりも <Text name="name" />のような使い方がしたい。
  • onChange onBlurをハンドリング

とりあえず作ってみる

inputField.js
import React from 'react';
import { InputGroup, Form } from 'react-bootstrap';
import { Field } from 'formik';

export const Text = ({
  prependText,
  appendText,
  name,
  ...props
}) => (
  <Field name={name} {...props}>
    {({
      field, 
      meta,
    }) => {
      return (
        <>
          <InputGroup>
            {prependText && (
              <InputGroup.Prepend>
                <InputGroup.Text> {prependText} </InputGroup.Text>
              </InputGroup.Prepend>
            )}
            <Form.Control
              type="text"
              {...props}
              {...field}
              isInvalid={meta.touched && meta.error}
            />
            {appendText && (
              <InputGroup.Append>
                <InputGroup.Text> {appendText} </InputGroup.Text>
              </InputGroup.Append>
            )}
            {meta.touched && meta.error && (
              <Form.Control.Feedback type="invalid">
                {meta.error}
              </Form.Control.Feedback>
             )}
          </InputGroup>
        </>
      );
    }}
  </Field>
);

上記、一件良さそうに見えます。しかも公式が推奨している書き方だし。でも、InputGroupを使うとコンポーネントの角が出てイケてないんです。こんな風になる。
スクリーンショット 2020-03-08 11.35.05.png

対策として以下の書き方をします。

<InputGroup>
  {prependText && (
    <InputGroup.Prepend>
      <InputGroup.Text> {prependText} </InputGroup.Text>
    </InputGroup.Prepend>
  )}
  <Form.Control
    type="text"
    {...props}
    {...field}
    onChange={handleChange}
    onBlur={handleBlur}
    isInvalid={meta.touched && meta.error}
  />
  {appendText && (
    <InputGroup.Append>
      <InputGroup.Text> {appendText} </InputGroup.Text>
    </InputGroup.Append>
  )}
</InputGroup>
{meta.touched && meta.error && (
  <InputGroup>
    <div className="invalid-feedback d-block">{meta.error}</div>
  </InputGroup>
)}

Formコンポーネントを使うのを止め、別のInputGroupに出して className="d-block"を使ってinvalid-feedbackクラスの display:noneを上書きします。これにより理想の出力となります。公式も修正した方が良いと思うんですけどね。

使うときはこんな感じ

<Text name="zipcode" type="tel" prependText="〒" />

以下のように表示されます。上手くいきました。
スクリーンショット 2020-03-08 12.25.39.png

onChange onBlurに対応させる

<Field />はデフォルトで onChange onBlurをフックしちゃうので一手間かけます。

export const Text = ({
  onChange,
  onBlur,
 /* 省略 */
}) => (
  <Field name={name} {...props}>
    {({
      field,
      meta,
    }) => {
      const handleChange = event => {
        if (onChange) {
          onChange(field.name, event.target.value);
        }
        field.onChange(field.name)(event);
      };
      const handleBlur = event => {
        if (onBlur) {
          onBlur(field.name, event.target.value);
        }
        field.onBlur(field.name)(event);
      };
      return (
         /* 省略 */
            <Form.Control
              type="text"
              {...props}
              {...field}
              onChange={handleChange}
              onBlur={handleBlur}
              isInvalid={meta.touched && meta.error}/>
         /* 省略 */
      );
    }}
  </Field>
);

これにより


import { Text } from '/path/to/inputFiled.js';

const handleChange = (fieldName,value ) => {

};

<Text onChange={(fieldName,value)=>handleChange(fieldName,value)} />

のような使い方ができます。まあ、onChangeが無くても Yupの拡張で何とかなるんですが。

発展

他にも

  • コンポーネント内のhandleBlurに記述を追加する事によって入力値の変換が可能になる。 <Katakana />コンポーネントとかが作成できます。handleChangeには入れない方が良いです。
  • react-number-formatと組み合わせて <Number /> <Dec /> 等が作成可能
  • react-datetime と組み合わせて <Date />

勢いに乗って <Radio /> <Checkbox /> <Select />なんかも作成しました。 <Number /><Date />は癖があって稼働までに苦労したので機会&&反応があれば別途記述したいですね。

最後に

今回の記述方法は他のUI FrameworkをFormikに対応させる場合にも応用できると思います。

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