formik-material-ui の素振り

先日、 [Typescript Deep Dive (日本語版)](https://typescript-jp.gitbook.io/deep-dive/) を読みました。react 経由で typescript に入ってきましたが、色々と追いついてなくてヤバイです。

それはそうと、**formik + material-ui** でググったら、material-ui をラップしたような [formik-material-ui](https://github.com/stackworx/formik-material-ui) があったので、これを素振りしてみました。

## 素振り

今回は、HOC として Formik を食わせる `withFormik` でやりました。
基本的には、`formik` の `Field` の `component` に、
`formik-material-ui` のコンポーネントを渡してあげればよさそうでした。

### Textfield

以下の画像の項目は TextField を渡すだけでできました。

<img width="620" alt="text_fields.png" src="https://qiita-image-store.s3.amazonaws.com/0/110426/ee928516-7268-b07d-12ce-015d97d07ffb.png">

```javascript
    <Field
      name="text"
      label="text *"
      type="text"
      component={TextField}
      value={values.text}
      onChange={handleChange}
      fullWidth={true}
    />
    <br />

    <Field
      name="email"
      label="email *"
      type="email"
      component={TextField}
      value={values.email}
      onChange={handleChange}
      fullWidth={true}
    />
    <br />

    <Field
      name="password"
      label="password *"
      type="password"
      component={TextField}
      value={values.password}
      onChange={handleChange}
      error={errors.password && touched.password}
      fullWidth={true}
    />
    <br />

    <Field
      name="textarea"
      label="textarea *"
      type="text"
      component={TextField}
      value={values.textarea}
      multiline={true}
      fullWidth={true}
    />
    <br />

    <Field
      name="select"
      label="select *"
      select={true}
      component={TextField}
      variant="outlined"
      InputLabelProps={{ shrink: true }}
    >
      {['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map((value, index) => (
        <MenuItem key={index} value={value}>
          {value}
        </MenuItem>
      ))}
    </Field>
    <br />

    <Field
      name="date"
      label="date *"
      type="date"
      InputLabelProps={{ shrink: true }}
      component={TextField}
      variant="outlined"
    />
    <br />
```

### ラジオ、チェックボックス系

<img width="620" alt="radiogroup.png" src="https://qiita-image-store.s3.amazonaws.com/0/110426/c27edea3-f843-32c8-317a-4452221d639c.png">


```javascript
    <Field
      name="gender"
      label="gender *"
      component={RadioGroup}
      values={values.gender}
      onChange={handleChange}
    >
      <FormControlLabel
        value="male"
        label="Male"
        control={<Radio disabled={isSubmitting} />}
        disabled={isSubmitting}
      />
      <FormControlLabel
        value="female"
        label="Female"
        control={<Radio disabled={isSubmitting} />}
        disabled={isSubmitting}
      />
      <FormControlLabel
        value="other"
        label="Other"
        control={<Radio disabled={isSubmitting} />}
        disabled={isSubmitting}
      />
    </Field>
    <br />
    <Field name="switch" label="switch" component={Switch} />
    <br />
    <Field name="checkbox" label="checkbox" component={Checkbox} />
    <br />
    <Field
      name="checkboxwithlabel"
      label="checkboxwithlabel"
      component={CheckboxWithLabel}
      Label={{ label: 'checkbox with label' }}
    />
    <br />
```

### ファイルアップロード系

プレビュー付きとかをやろうとすると、面倒なのことになるので、
そういうときは素直に `Dropzone` とかで片付けたほうがよさげです。

```javascript
    <Field component={SimpleFileUpload} name="upload_file" />
    <br />

    <Field
      name="file"
      type="file"
      onChange={(e: any) => {
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.onload = (item: any) => {
          setFieldValue('file_data', item.target.result);
        };

        reader.readAsDataURL(file);
      }}
    />

    <DropzoneArea
      onChange={acceptedFiles => {
        setFieldValue('files', acceptedFiles);
        acceptedFiles.map((f: any, index: number) => {
          const reader = new FileReader();
          reader.onload = (item: any) => {
            setFieldValue(`files_data${index}`, item.target.result);
          };
          reader.readAsDataURL(f);
        });
      }}
    />
    <br />
```

<img width="620" alt="files.png" src="https://qiita-image-store.s3.amazonaws.com/0/110426/71510e2a-07b9-0960-033c-9d54af17c9b5.png">


## 参考にしたドキュメント等

- [jaredpalmer/formik](https://github.com/jaredpalmer/formik)
- [stackworx/formik-material-ui](https://github.com/stackworx/formik-material-ui)
- [react-dropzone/react-dropzone](https://github.com/react-dropzone/react-dropzone)
  - [プレビュー付きのゾーンのサンプルとか](https://react-dropzone.js.org/#examples)
- [Yuvaleros/material-ui-dropzone](https://github.com/Yuvaleros/material-ui-dropzone)
- [oukayuka/UserSearchForm.tsx](https://gist.github.com/oukayuka/1ef7278c466fe926496ac2181a029f97)
- [Formik — Handling files and reCaptcha](https://hackernoon.com/formik-handling-files-and-recaptcha-209cbeae10bc)

## コード

いろいろ試して遊んでいたので、汚い dispatch 等々が入ってます。

[uitspitss/formik_mui_practice](https://github.com/uitspitss/formik_mui_practice)