Make it to make it

いろいろ作ってアウトプットするブログ

Flowによるreactの静的型付け

今までPropTypesやTypeScriptによる静的型付けを述べてきたが、今回はFlowを用いた実装をしてみる。

flow.org

次のようなディレクトリ構造で、5つ星評価のUI実装を考える。

.
├── Stars.css
└── Stars.js

インストール

インストール方法は公式ドキュメントに丁寧に書いてあるので割愛。

セットアップ

npm install --save-dev flow-bin

package.jsonに次のnpm scriptsを追加。

  "scripts": {
    "flow": "flow"
  }

まず最初にnpm run flow initを実行して.flowconfigを生成する。

それ以降は適宜npm run flowを実行しながら開発を進めていく。他のnpm scriptsと合わせて実行したり、nodemonなどと組み合わせたりすると便利そう。

実装

font-awesomeのアイコンを使いたいので、react-iconsをインストールする。

npm install react-icons

Stars.css

.stars {
  display: inline-flex;
}

.stars .star:not(:first-of-type) {
  margin-left: 3px;
}

.star {
  background-color: transparent;
  border: none;
  cursor: pointer;
  outline: none;
  padding: 0;
  appearance: none;
}

Stars.js

// @flow
import * as React from 'react';
import { FaStar } from 'react-icons/fa';
import './Stars.css';

type Props = {
  rating?: number,
};

type State = {
  rating: number,
  colorArray: Array<string>,
};

class Stars extends React.Component<Props, State> {
  constructor(props) {
    super(props);

    this.defaultColor = '#d7d7d7';
    this.selectedColor = '#55c500';

    this.state = {
      rating: this.props.rating,
      colorArray: Array(5)
        .fill()
        .map(() => this.defaultColor),
    };
  }

  componentDidMount() {
    this.updateColor(this.state.rating - 1);
  }

  updateColor = index => {
    const { colorArray } = this.state;

    for (let i = 0; i <= index; i += 1) {
      colorArray[i] = this.selectedColor;
    }
    for (let j = index + 1; j < 5; j += 1) {
      colorArray[j] = this.defaultColor;
    }

    this.setState({
      colorArray,
    });
  };

  render() {
    const { colorArray } = this.state;

    return (
      <div className="stars">
        {colorArray.map((c, i) => (
          <button
            type="button"
            className="star"
            onClick={() => this.updateColor(i)}
            key={i}
          >
            <FaStar color={c} size={24} />
          </button>
        ))}
      </div>
    );
  }
}

Stars.defaultProps = {
  rating: 3,
};

export default Stars;

@flowと先頭に記述するファイルが、型バリデーションの対象となる。

VSCodeを使用している場合、下記のエクステンションを入れれば、fccで一発展開してくれる。 (Class component with flow types skeleton)

marketplace.visualstudio.com

type Propsでpropsのアノテーションtype Stateでstateのアノテーションができる。defaultPropsなどと組み合わせて適宜使う。

使えるアノテーション一覧はこちらを参照のこと。

TypeScriptよりは簡単に実装できるが、TSのようにType Inferenceが効いていないのではないかと思われる。

あとは、とにかくドキュメントが簡潔でわかりやすいところがよい。

後書き

軽い実装の練習がてらFlowを試してみたが、今の世の中のトレンドとしては圧倒的にTypeScriptなので、学ぶならやっぱりTypeScriptの方がベター。