Casual Developers Note

エンジニアやデザイナー向けの技術情報・英語学習情報・海外留学情報・海外旅行情報を提供中。世界を旅して人生を楽しもう。

  • ホーム
  • 技術 Tips & Tutorials
  • 技術塾
  • ライフハック
  • 海外留学
  • 英語学習
  • コラム
  • お問い合わせ
現在の場所:ホーム / アーカイブreact

2019年10月30日 By KD コメントを書く

ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

Reactの開発環境でEslintおよびPretteirを設定する方法を紹介します。

はじめに

JavaScriptのコードフォーマッターと言えば「Eslint」と「Pretteir」を組み合わせるのが主流です。今回は、以前の記事「Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)」をインプットにして、React用にゼロからEslintおよびPretteirを設定する方法を紹介します。

それでは、ReactにEslintおよびPrettierを設定していきましょう。

JavaScriptのコーディングスタイル

JavaScriptのコーディングスタイルは以下の3つが代表的です。

  • Airbnb JavaScript Style Guide
  • Google JavaScript Style Guide
  • JavaScript Standard Style

どれを使うのがベストか?ということになりますが、コーディングスタイルは主観に大きく左右されるので、綺麗な解を出すのは難しいです。なので、強い個人的な主張がなければ、それぞれのコーディングスタイルの特徴を理解した上で、どれが人気か?ということを見て判断するのが良いでしょう。尖ったスタイルは後でEslintとPretteirでカスタマイズできますからね。そこで、これらのコーディングスタイルを比較しているサイトとして「Comparing eslint-config-airbnb vs. eslint-config-google vs. standard」を見てみましょう。このサイトの結果では、Airbnbのコーディングスタイルが一番人気があり良さそうです。

ということで、今回はコーディングスタイルとして「Airbnb JavaScript Style Guide」を適用します。

ReactにEslintおよびPrettierを設定する

前提

以下の設定が事前に完了している必要があります。

  • NodeJSがインストールされていること
  • 「Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)」の設定が完了していること

EslintおよびPretteirのモジュールをインストールする

ReactのプロジェクトにEslint、Pretteir、関連モジュールをインストールします。

$ cd my-react-app
$ yarn add --dev eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-jest eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-hooks
$ yarn add --dev eslint-plugin-babel eslint-plugin-flowtype
$ yarn add --dev babel-eslint eslint-loader
$ yarn add --dev prettier eslint-config-prettier eslint-plugin-prettier
$ yarn add --dev husky lint-staged

Pretteirの設定をする

Pretteirの設定ファイルを作成し、設定を書きます。

$ touch prettier.config.js

prettier.config.js

module.exports = {
  trailingComma: 'es5',
  tabWidth: 2,
  semi: false,
  singleQuote: true,
}

流行りのセミコロン無しの設定にしています。

また、設定ファイルのフォーマットは、Pretteirに限らず、JSON、YAML、JavaScriptが選択可能になっていることが多いですが、結局JavaScriptで設定ファイルを書くのが一番使いやすいと感じています。コメントが書けたり、設定を整理したい時に便利だからです。

Eslintの設定をする

Eslintの設定ファイルを作成して、設定を書きます。

$ yarn eslint --init
...
? How would you like to use ESLint? To check syntax, find problems, and enforce code style
? What type of modules does your project use? JavaScript modules (import/export)
? Which framework does your project use? React
? Does your project use TypeScript? No
? Where does your code run? Browser
? How would you like to define a style for your project? Use a popular style guide
? Which style guide do you want to follow? Airbnb (https://github.com/airbnb/javascript)
? What format do you want your config file to be in? JavaScript
Checking peerDependencies of eslint-config-airbnb@latest
The config that you've selected requires the following dependencies:
...
? Would you like to install them now with npm? No
...

.eslintrc.js

module.exports = {
  env: {
    browser: true,
    es6: true,
    jest: true,
  },
  extends: [
    'airbnb',
    'airbnb/hooks',
    'plugin:flowtype/recommended',
    'plugin:jest/recommended',
    'plugin:jest/style',
    'prettier',
    'prettier/babel',
    'prettier/react',
    'prettier/flowtype',
  ],
  globals: {
    Atomics: 'readonly',
    SharedArrayBuffer: 'readonly',
  },
  parser: 'babel-eslint',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 2018,
    sourceType: 'module',
  },
  plugins: ['babel', 'flowtype', 'jest', 'prettier'],
  rules: {
    'prettier/prettier': 'error',
    'react/jsx-filename-extension': 'off',
    'react/prop-types': 'off',
    'react/default-props-match-prop-types': 'off',
    'react/require-default-props': 'off',
    'flowtype/no-types-missing-file-annotation': 'off',
    'flowtype/define-flow-type': 'warn',
    'flowtype/use-flow-type': 'warn',
  },
}

自動作成された設定に、Babel、Flow、Jest、Pretteirのための設定を追加してあります。

Webpackに設定を追加する

Webpackで開発中にEslintを毎回実行するようにローダーの設定を追加します。

$ vi webpack.config.babel.js
{
...
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'eslint-loader',
        options: {
          fix: true,
        },
      },
...
    ],
  },
...
}

コミット時にリンターを実行する設定をする

コミット時に必ずチェックするようにしておけば安心です。

$ vi package.json
{
...
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "src/**/*.{js,jsx}": [
      "yarn eslint --fix",
      "git add"
    ]
  },
...
}

以上で完了です。あとは、エラーがになる箇所があればルールに従って修正していってください。

最後に

いかがでしたか?これでゼロからReact用にEslintおよびPretteirを設定できるようになったことでしょう。それでは。

環境

  • NodeJS: v12.12.0
  • eslint: 6.6.0
  • eslint-config-airbnb: 18.0.1
  • eslint-plugin-import: 2.18.2
  • eslint-plugin-jest: 23.0.2
  • eslint-plugin-jsx-a11y: 6.2.3
  • eslint-plugin-react: 7.16.0
  • eslint-plugin-react-hooks: 2.2.0
  • eslint-plugin-babel: 5.3.0
  • eslint-plugin-flowtype: 4.3.0
  • babel-eslint: 10.0.3
  • eslint-loader: 3.0.2
  • prettier: 1.18.2
  • eslint-plugin-prettier: 3.1.1
  • eslint-config-prettier: 6.5.0
  • husky: 3.0.9
  • lint-staged: 9.4.2

カテゴリ : 技術 Tips & Tutorials タグ : eslint, prettier, react, webpack

2019年9月30日 By KD コメントを書く

Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

create-react-appを使わないでReactの開発環境を構築する方法を紹介します。

はじめに

近年のJavaScriptフレームワークはCLIを使ってワン・コマンドで設定できるようになっています。Reactではそのためのコマンドとしてcreate-react-appが提供されています。creat-react-appは簡単にReactを設定できる反面、設定が隠蔽されてしまい、細かい設定をするためにはejectする羽目になります。しかし、ejectをしてしまえば最後、create-react-appがアップデートされてもアップデートできなくなってしまいます。では、プロダクションなどで設定を細かく設定して管理したい場合はどうすればよいでしょうか?そういう人は自分でゼロから設定しましょう。

ということで、今回はcreate-react-appを使わないで、Reactの開発環境を構築していきましょう。

Reactの開発環境の構築方法

それでは、Reactの設定をしましょう。

前提

以下の設定が完了している必要があります。

  • NodeJSがインストールされていること
  • Yarnがインストールされていること
  • Dockerがインストールしていること

詳しくは、「環境」を参照して下さい。

ベースの作成とパッケージのインストール

必要なフォルダおよびファイルを作成し、必要なパッケージをインストールします。

$ mkdir my-react-app
$ cd my-react-app/
$ yarn init -y
$ mkdir public src
$ touch public/index.html
$ touch src/index.js src/index.css
$ touch src/App.js src/App.test.js src/App.css
$ touch .babelrc webpack.config.babel.js
$ touch jest.config.js
$ mkdir __mocks__
$ touch __mocks__/styleMock.js
$ touch __mocks__/fileMock.js
$ yarn add --dev flow-bin flow-typed
$ yarn flow init
$ tree -aI node_modules
.
├── .babelrc
├── .flowconfig
├── __mocks__
│   ├── fileMock.js
│   └── styleMock.js
├── build
├── jest.config.js
├── package.json
├── public
│   └── index.html
├── src
│   ├── App.css
│   ├── App.js
│   ├── App.test.js
│   ├── index.css
│   └── index.js
├── webpack.config.babel.js
└── yarn.lock
$ yarn add react react-dom
$ yarn add --dev jest jest-enzyme enzyme enzyme-adapter-react-16
$ yarn add --dev @babel/core @babel/preset-env @babel/preset-react @babel/preset-flow @babel/register babel-jest
$ yarn add --dev webpack webpack-cli webpack-dev-server
$ yarn add --dev html-webpack-plugin mini-css-extract-plugin uglifyjs-webpack-plugin optimize-css-assets-webpack-plugin clean-webpack-plugin
$ yarn add --dev babel-loader css-loader html-loader
$ vi package.json
...
  "scripts": {
    "start": "webpack-dev-server --open --mode development",
    "build": "webpack --mode production",
    "test": "jest"
  }
...

準備ができました。

設定を書く

それでは、ファイルの中身を書いていきましょう。

.babelrc

{
  "presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-flow"]
}

jest.config.js

module.exports = {
  moduleNameMapper: {
    '\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
      '/__mocks__/fileMock.js',
    '\.(css|less)$': '/__mocks__/styleMock.js',
  },
};

__mocks__/styleMock.js

module.exports = {};

__mocks__/fileMock.js

module.exports = 'test-file-stub';

.flowconfig

[ignore]
.*/node_modules/.*
.*/flow-typed/.*
.*/build/.*
.*\.(test|spec)\.js
.*/build/.*
.*webpack.*
.*jest\.config\.js
<PROJECT_ROOT>/src/index\.js

[include]

[libs]

[lints]

[options]
all=true

[strict]

webpack.config.babel.js

import path from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import UglifyJsPlugin from 'uglifyjs-webpack-plugin';
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
import { CleanWebpackPlugin } from 'clean-webpack-plugin';

const outputPath = path.resolve(__dirname, 'build');

export default {
  entry: './src/index.js',
  output: {
    filename: '[name].[hash].js',
    path: outputPath,
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
      },
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
      {
        test: /\.html$/,
        loader: 'html-loader',
      },
    ],
  },
  devServer: {
    contentBase: outputPath,
    compress: true,
    port: 3000,
  },
  devtool: 'eval-source-map',
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[hash].css',
    }),
    new CleanWebpackPlugin(),
  ],
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        uglifyOptions: {
          compress: {
            drop_console: true,
          },
        },
      }),
      new OptimizeCSSAssetsPlugin(),
    ],
  },
};

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>My React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(, document.getElementById('root'));

index.css

* {
  margin: 0;
}

App.js

import React, { useState } from 'react';
import './App.css';

type Props = {
  initialCount: number,
};

function App({ initialCount }: Props) {
  const [count, setCount] = useState(initialCount);

  return (
    <div className="App" data-test="component-app">
      <header className="App-header">
        <p>My React App without Create React App!</p>
        <p>Count: {count}</p>
        <div>
          <button onClick={() => setCount(count + 1)}>+1</button>
          <button onClick={() => setCount(count - 1)}>-1</button>
          <button onClick={() => setCount(initialCount)}>clear</button>
        </div>
      </header>
    </div>
  );
}

App.defaultProps = {
  initialCount: 0,
};

export default App;

App.css

.App {
  text-align: center;
}

.App-header {
  background-color: #09d3ac;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 4vmin);
  color: white;
}

button {
  margin: 0 5px;
  padding: 10px;
  width: 200px;
  font-size: calc(10px + 4vmin);
  border-radius: 10px;
}

App.test.js

import React from 'react';
import Enzyme, { shallow } from 'enzyme';
import EnzymeAdapter from 'enzyme-adapter-react-16';
import App from './App';

Enzyme.configure({ adapter: new EnzymeAdapter() });

it('renders without crashing', () => {
  const wrapper = shallow(<App />);
  const appComponent = wrapper.find(`[data-test="component-app"]`);

  expect(wrapper).toBeTruthy();
  expect(appComponent.length).toBe(1);
});

完成です。

今回のWebpackの設定は開発用とプロダクション用で分けていませんが、実際には分けて作り、webpack-mergeなどを使って共通化すると良いでしょう。

今回のJestの設定は公式ドキュメントの通りにしてあります。

なお、EslintやPrettierもプロジェクトのスタイリングルールに応じて設定した方が良いでしょう。

動作確認

まずは開発環境を起動してみましょう。

$ yarn start
...
ℹ 「wds」: Project is running at http://localhost:3000/
...
ℹ 「wdm」: Compiled successfully.

ブラウザで「localhost:3000」が表示されます。

NewImage

カウンターの動作確認もしてみましょう。

NewImage

NewImage

NewImage

OKですね。

次に、テスト実行してみましょう。

$ yarn test
...
 PASS  src/App.test.js
  ✓ renders without crashing (10ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.667s
Ran all test suites.
✨  Done in 7.68s.

テストもパスしました。

最後に、ビルドしてみましょう。

$ yarn build
$ ls build/
index.html                     main.babca1870d3e34b4c183.css  main.babca1870d3e34b4c183.js

ビルドも成功しました。

これで、Reactの設定は完了しました。

Docker化する方法

それでは、Docker上で起動するようにしていきましょう。

ファイルの作成

必要なファイルを作成します。

$ touch Dockerfile.dev docker-compose.yml

設定を書く

Dockerの設定を書きましょう。

Dockerfile.dev

FROM node:12.10-alpine

WORKDIR /app

RUN apk update \
  && apk --no-cache add git ca-certificates wget

RUN wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub \
  && wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.30-r0/glibc-2.30-r0.apk \
  && apk --no-cache add glibc-2.30-r0.apk

COPY package.json .
COPY yarn.lock .
RUN yarn install

COPY .flowconfig .
RUN yarn global add flow-typed \
  && flow-typed install

COPY . .

EXPOSE 3000

CMD yarn start

docker-compose.yml

version: "3"

services:
  web:
    command: "yarn start --host 0.0.0.0 --port 3000"
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - /app/node_modules
      - .:/app

完成です。

FlowはAlpine上で実行する際に問題があり、こちらにissueが発行されています。結局、glibcを入れるか、flowのバイナリーを入れるかで対処する必要があり、今回は前者にしました。

動作確認

Dockerで起動できるか確認してみましょう。

$ docker-compose build --no-cache
$ docker-compose up -d
$ docker-compose ps
       Name                     Command               State           Ports         
------------------------------------------------------------------------------------
my-react-app_web_1   docker-entrypoint.sh yarn  ...   Up      0.0.0.0:3000->3000/tcp

ブラウザで「localhost:3000」を開けば、正しく表示されます。

これでDocker化まで完了しました。

おまけ

さらに、Webpackに開発用の設定を追加していきましょう。

画像を読み込むための設定

画像などのアセットを読み込むための設定を追加します。画像をWebpackで利用するには、url-loaderおよびfile-loaderのローダーを追加します。

$ yarn add --dev file-loader url-loader
$ vi webpack.config.babel.js
{
...
  module: {
    rules: [
...
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10 * 1024,
              name: '[name].[hash:8].[ext]',
              outputPath: 'assets',
            },
          },
        ],
      },
...
    ],
  },
...
}

「url-loader」でファイルをbase64に変換してCSSに埋め込みます。ファイルのサイズがリミットを超える場合は「file-loader」でファイルをそのまま読み込みます。base64はファイルを都度読み込む必要がないのでページの読み込みを早くできますが、常にファイルをそのまま扱いたい場合は「file-loader」だけで良いです。

Polyfillの設定方法

古いブラウザに対応するために、BabelにPolyfillを追加しましょう。

$ yarn add core-js@3

.babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ],
    "@babel/preset-react",
    "@babel/preset-flow"
  ]
}

@babel/polyfillはBabelの7.4.0から非推奨になっています。上記の設定で、必要なPolyfillだけをcorejsからインポートして使われるようになります。詳しくは、公式ドキュメントを参照して下さい。

HMR(Hot Module Replacement)の設定方法

webpack-dev-serverでは、デフォルトでdevServer.inlineが有効になっており、ライブリロードが実行されます。ライブリロードはソースコードを修正するたびにブラウザをリロードする機能ですが、一つのコンポーネントを修正するたびにブラウザをリロードするのは効率がよくありません。そこで、HMR(Hot Module Replacement)を有効することで、リロードすることなく、修正したコンポーネントだけ更新するようにしましょう。

webpack.config.babel.js (抜粋)

...
import webpack from 'webpack';
...

export default {
...
  devServer: {
    ...
    hot: true,
    ...
  },
...
  plugins: [
    ...
    new webpack.HotModuleReplacementPlugin(),
  ],
...
};

devServer.hotを有効にし、かつ、HotModuleReplacementPluginを設定しました。

起動してみると、以下のようにHMRが有効になっていることが分かります。

NewImage

react-hot-loaderの設定方法

Stateを保持したままコンポーネントの修正を反映するために、react-hot-loaderおよび@hot-loader/react-domを設定しましょう。

$ yarn add react-hot-loader @hot-loader/react-dom

.babelrc (抜粋)

{
  "plugins": ["react-hot-loader/babel"],
...
}

webpack.config.babel.js (抜粋)

...

export default {
...
  resolve: {
    alias: {
      'react-dom': '@hot-loader/react-dom',
    },
  },
};

App.js (抜粋)

...
import { hot } from 'react-hot-loader/root';
...
export default hot(App);

最後に

いかがでしたか?これでcreate-react-appに頼ることなく、自分でReactを設定できるようになったことでしょう。それでは。

環境

  • NodeJS: v12.11.0
  • Yarn: 1.17.3
  • Docker: 19.03.2
  • react: 16.10.0
  • react-dom: 16.10.0
  • react-hot-loader: 4.12.14
  • @hot-loader/react-dom: 16.9.0
  • core-js: 3
  • @babel/core: 7.6.2
  • @babel/preset-env: 7.6.2
  • @babel/preset-flow: 7.0.0
  • @babel/preset-react: 7.0.0
  • @babel/register: 7.6.2
  • babel-jest: 24.9.0
  • jest: 24.9.0
  • jest-enzyme: 7.1.1
  • enzyme: 3.10.0
  • enzyme-adapter-react-16: 1.14.0
  • flow-bin: 0.108.0
  • flow-typed: 2.6.1
  • webpack: 4.41.0
  • webpack-cli: 3.3.9
  • webpack-dev-server: 3.8.1
  • clean-webpack-plugin: 3.0.0
  • html-webpack-plugin: 3.2.0
  • optimize-css-assets-webpack-plugin: 5.0.3
  • uglifyjs-webpack-plugin: 2.2.0
  • mini-css-extract-plugin: 0.8.0
  • babel-loader: 8.0.6
  • css-loader: 3.2.0
  • html-loader: 0.5.5
  • url-loader: 2.2.0
  • file-loader: 4.2.0

カテゴリ : 技術 Tips & Tutorials タグ : babel, create-react-app, docker, flow, hot-module-replacement, polyfill, react, webpack

2019年4月12日 By KD コメントを書く

FormikでReactのフォームを華麗に扱う方法

FormikでReactのフォームを華麗に扱う方法

Reactのフォーム用ライブラリ「Formik」でフォームを華麗に扱う方法を紹介します。

はじめに

Reactでフォームを扱う場合、ライブラリを使わないとソースコードが煩雑になってしまいます。React/Reduxの環境でポピュラーなフォーム用のライブラリといえば「Redux Form」ですが、Redux自体は必須というわけではなく、Reactのみでフロントエンドを構築する場合もあるため、Reduxを前提としたフォーム用ライブラリを使うと、React/Reduxで構築したアプリケーションをReactのみに書き直した場合などにコンポーネントの再利用性を低下させてしまいます。そこで、Reduxとは関係のないReactのフォーム用ライブラリとして「Formik」という選択肢が出てきます。

今回は、「Formik」を使って、Reactのフォームを扱う方法を紹介します。

Formikとは?

「Formik」とは、単独で利用可能なReactのフォーム用ライブラリです。

前提

以下の準備が完了している必要があります。

  • NodeJSがインストールされていること
  • create-react-appがインストールされていること

細かいバージョンは「環境」を参照してください。

FormikでReactのフォームを作成する

ベースを作る

まずは、Reactのプロジェクトを作成し、必要なパッケージをインストールします。

$ npx create-react-app formik-sample
$ cd formik-sample/
$ rm src/App.css
$ rm src/App.test.js
$ rm src/logo.svg
$ touch src/MyForm.js
$ yarn add formik yup bootstrap reactstrap
$ tree -aI 'node_modules|.git'
.
├── .gitignore
├── README.md
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
├── src
│   ├── App.js
│   ├── MyForm.js
│   ├── index.css
│   ├── index.js
│   └── serviceWorker.js
└── yarn.lock

フォームを実装する

入力チェック付きのフォームを実装しましょう。

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));

serviceWorker.unregister();

index.css

body {
  text-align: center;
  font-size: 1.5rem;
  padding: 3%;
}

App.js

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

const App = () => (
  <>
    <MyForm />
  </>
);

export default App;

MyForm.js

import React from 'react';
import {
Button,
Form,
FormGroup,
Label,
Input as ReactstrapInput,
FormFeedback,
} from 'reactstrap';
import { withFormik, ErrorMessage, Field } from 'formik';
import * as yup from 'yup';
const Input = ({ name, ...others }) => (
<Field
name={name}
render={({ field }) => <ReactstrapInput {...field} {...others} />}
/>
);
const ErrorFormFeedback = ({ name }) => (
<ErrorMessage
name={name}
component={({ children }) => <FormFeedback>{children}</FormFeedback>}
/>
);
const ErrorInnerMessage = ({ name }) => (
<ErrorMessage
name={name}
component={({ children }) => (
<span className="text-danger" style={{ fontSize: '1.2rem' }}>
{children}
</span>
)}
/>
);
const MyForm = ({
handleSubmit,
handleReset,
isSubmitting,
dirty,
errors,
touched,
}) => (
<div className="mx-auto col-8">
<h2>My Form</h2>
<Form className="text-left" onSubmit={handleSubmit}>
<FormGroup className="mb-2">
<Label for="myEmail">Email</Label>
<Input
type="email"
name="email"
id="myEmail"
placeholder="Enter email"
valid={dirty && !errors.email}
invalid={touched.email && !!errors.email}
/>
<ErrorFormFeedback name="email" />
</FormGroup>
<FormGroup className="mb-2">
<Label for="myUsername">Username</Label>
<Input
type="text"
name="username"
id="myUsername"
placeholder="Enter username"
valid={dirty && !errors.username}
invalid={touched.username && !!errors.username}
/>
<ErrorFormFeedback name="username" />
</FormGroup>
<FormGroup className="mb-2">
<Label for="myPassword">Password</Label>
<Input
type="password"
name="password"
id="myPassword"
placeholder="Enter password"
valid={dirty && !errors.password}
invalid={touched.password && !!errors.password}
/>
<ErrorFormFeedback name="password" />
</FormGroup>
<FormGroup className="mb-2" tag="fieldset">
<legend>Gender</legend>
<FormGroup inline check>
<Label check>
<Input type="radio" name="gender" value="male" />
male
</Label>
</FormGroup>
<FormGroup inline check>
<Label check>
<Input type="radio" name="gender" value="female" />
female
</Label>
</FormGroup>
<span className="ml-3">
<ErrorInnerMessage name="gender" />
</span>
</FormGroup>
<FormGroup check className="mb-2">
<Input type="checkbox" name="isAccepted" id="myCheck" />
<Label for="myCheck" check>
Accept
</Label>
<span className="ml-3">
<ErrorInnerMessage name="isAccepted" />
</span>
</FormGroup>
<div className="d-flex justify-content-center">
<span className="p-2">
<Button
type="button"
outline
color="secondary"
onClick={handleReset}
disabled={!dirty || isSubmitting}
>
Reset
</Button>
</span>
<span className="p-2">
<Button type="submit" outline color="primary" disabled={isSubmitting}>
Submit
</Button>
</span>
</div>
</Form>
</div>
);
const MyEnhancedForm = withFormik({
mapPropsToValues: () => ({
username: '',
email: '',
password: '',
gender: '',
isAccepted: false,
}),
handleSubmit: (values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 3000);
},
validationSchema: yup.object().shape({
email: yup
.string()
.email('Enter a correct email ')
.required('Enter an email'),
username: yup
.string()
.min(3, 'A username must contain more than 3 characters')
.required('Enter a username'),
password: yup
.string()
.min(8, 'A username must contain more than 8 characters')
.required('Enter a password'),
gender: yup
.string()
.oneOf(['male', 'female'])
.required('Check a gender'),
isAccepted: yup.boolean().oneOf([true], 'Must accept terms and conditions'),
}),
})(MyForm);
export default MyEnhancedForm;

Formikの実装方法は、Formikコンポーネントでそのままフォームを実装するシンプルな方法と、withFormikコンポーネントでフォームのコンポーネントをラップするHOC(higher-order component)の方法があります。今回は実際に使うことが多い後者のHOCの方法で実装しています。

動作確認

それでは、アプリケーションを起動し、フォームの入力チェックが正しく動くか確認しましょう。

$ yarn start

NewImage

入力チェックが正しく行われるか確認します。

NewImage

正しいデータが入力されたこを確認します。

NewImage

「Submit」ボタンをクリックして、入力したデータが表示されることを確認します。

NewImage

OKですね。

最後に

いかがでしたか?これでReduxに依存すること無く、「Formik」でReactのフォームを華麗に扱うことができるようになったのではないでしょうか。それでは。

環境

  • NodeJS: v11.13.0
  • create-react-app: 2.1.8
  • bootstrap: 4.3.1
  • reactstrap: 8.0.0
  • formik: 1.5.2
  • yup: 0.27.0

カテゴリ : 技術 Tips & Tutorials タグ : formik, react, yup

  • 1
  • 2
  • 3
  • 4
  • 次のページ »

ブログ更新情報や海外の関連情報などを配信する無料メルマガ

Sponsored Links

About Author

KD

世界を旅し日本を愛するエンジニア。大学でコンピュータサイエンスの楽しさを学び、日本の大手IT企業で働く中で、新しい技術やスケールするビジネスが北米にある事に気づく。世界に挑戦するための最大の壁が英語であったため、フィリピン留学およびカナダ留学を経て英語を上達させた。現在は日本在住でエンジニアとして働きつつ、次の挑戦に備えて世界の動向を注視している。挑戦に終わりはない。このブログでは、エンジニアやデザイナー向けの技術情報から、海外に留学したい人向けの留学情報、海外に興味がある人向けの海外旅行情報など、有益な情報を提供しています。

https://casualdevelopers.com/

最近の投稿

  • 2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介

    2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介

    2020年1月13日
  • 今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~

    今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~

    2019年11月4日
  • ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

    ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

    2019年10月30日
  • BashからZshに移行する方法(Mac編)

    BashからZshに移行する方法(Mac編)

    2019年10月21日
  • Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

    Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

    2019年9月30日

カテゴリ

  • 技術 Tips & Tutorials (100)
  • 技術塾 (6)
  • ライフハック (26)
  • 海外留学 (12)
  • 英語学習 (3)
  • コラム (6)

アーカイブ

最高の学習のために

人気記事ランキング

  • MySQLで「ERROR 2003 (HY000): Can't connect to MySQL server」と怒られた時の対処法
    MySQLで「ERROR 2003 (HY000): Can't connect to MySQL server」と怒られた時の対処法
  • SAKURAのメールボックスで独自ドメインのメールを設定し、Gmail経由で送受信する方法
    SAKURAのメールボックスで独自ドメインのメールを設定し、Gmail経由で送受信する方法
  • Expressで「Cannot set headers after they are sent to the client」と怒られた時の対処法
    Expressで「Cannot set headers after they are sent to the client」と怒られた時の対処法
  • AWS ECRとECSの入門(EC2編) ~ ECSのEC2版を使ってReactのDockerアプリケーションをAWS上で稼働させる方法 ~
    AWS ECRとECSの入門(EC2編) ~ ECSのEC2版を使ってReactのDockerアプリケーションをAWS上で稼働させる方法 ~
  • 爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~
    爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~
  • Amazon EC2インスタンスにSSHできなくなった時の対処法
    Amazon EC2インスタンスにSSHできなくなった時の対処法
  • Jupyter Notebookで「The kernel appears to have died. It will restart automatically.」というエラーが出た場合の原因と対処法
    Jupyter Notebookで「The kernel appears to have died. It will restart automatically.」というエラーが出た場合の原因と対処法
  • バンクーバー留学豆知識:バンクーバーのATMで日本の銀行のキャッシュカードを使ってお得にお金を引き出す方法
    バンクーバー留学豆知識:バンクーバーのATMで日本の銀行のキャッシュカードを使ってお得にお金を引き出す方法
  • [tips][bat] バッチで明日の日付を計算する。
    [tips][bat] バッチで明日の日付を計算する。
  • [tips][perl] Perlで文字コードをいい感じに処理する方法
    [tips][perl] Perlで文字コードをいい感じに処理する方法

Bitcoin寄付 / BTC Donation

Bitcoinを寄付しよう

BTC
Select Payment Method
Personal Info

Donation Total: BTC 0.0010

このブログの運営のためにBitcoinでの寄付を募集しています。お気持ち程度の寄付を頂けると管理者の励みになります。

Bitcoin寄付について知りたい方はこちらの記事へ

ビットコイン取引ならここ

  • ホーム
  • 技術 Tips & Tutorials
  • 技術塾
  • ライフハック
  • 海外留学
  • 英語学習
  • コラム
  • サイトマップ
  • タグ一覧
  • プライバシーポリシー
  • お問い合わせ

Copyright © 2023 KD - Casual Developers Notes