React 初心者が初級者になるまで

# はじめに
この記事は [ACCESS Advent Calendar 2016](http://qiita.com/advent-calendar/2016/access) 25 日目 最後の記事になります。

クリスマスですね、いかがお過ごしでしょうか。

今日は *React 初心者が初級者になるまで* というタイトルで、初級者になったつもりのわたくし @kasaharu がお届けいたします。

さっそく始めていきます。

# 2017 年こそ React を触りたい人が知っておきたいこと

## :one: props

* props はコンポーネントに渡す任意のプロパティを指す
    * そのときの型は string, number, function, node などが指定できる

```js
// 金額を表示する Currency コンポーネントに
// 表示する金額のための変数 amount と
// 金額を変更するためのイベントハンドラ editAmount() を渡す場合
<Currency
  amount={amount}
  onChange={this.editAmount}
/>
```

### PropTypes

* 呼び出されるコンポーネント側では親から渡される props のバリデーションが可能

```js
propTypes() {
  return {
    amount: React.PropTypes.number.isRequired,
    onChange: React.PropTypes.func,
  }
}
```

* 型のチェックだけでなく、その props が必須か任意かの指定も出来る

### 指定可能な PropTypes の例

```js
// 数値
React.PropTypes.number
// 文字列
React.PropTypes.string
// 関数
React.PropTypes.func
// 要素が文字列型の配列
React.PropTypes.arrayOf(React.PropTypes.string)
// 数値または文字列のどちらか
React.PropTypes.oneOfType([React.PropTypes.number, React.PropTypes.string])
```

* その他詳細は [公式ページ](https://facebook.github.io/react/docs/typechecking-with-proptypes.html#react.proptypes) を参照

**props で気にしたいこと**

* PropTypes を指定せよ

## :two: state について

* コンポーネント内の状態を持つときに使用される

```js
check() {
 this.setState({ checked: !this.state.checked });
}

render() {
  return (
    <input
      type="checkbox"
      onChange={this.check}
      checked={this.state.checked}
    />
  );
}
```

* checkbox の状態を持つときなどに使用すると便利
* 状態の変更には `setState()` を使用する必要がある
    * 直接 `this.state.xxx` を変更するのは禁止されている
    * `setState()` を使用することで react が状態変更後に再描画処理を実施するが、 `setState()` を使わないで state を更新しようとすると、期待したように描画されなかったりする
* コンポーネントごとに状態を管理できるので楽に使えるが、多用すると状態の管理が複雑になるので出来る限り使わないほうが望ましい
    * state の代わりに props を使い、 props を一箇所で管理したほうがよい

**state で気にしたいこと**

* 本当に state を使うポイントなのか？ props ではダメなのか？を検討した上で使用する

## :three: list 表示時の key について
### Virtual DOM
* 本当の DOM と同様のツリーを構成をした JS のオブジェクト
    * JS のオブジェクトなので変更処理などが、通常の DOM に比べ早い
* 画面を変更する処理をした場合、以下のようなイメージで処理が走る
    * 各種パラメータを新しい状態(state)にして Virtual DOM を作成
    * 変更前の Virtual DOM と変更後の Virtual DOM を比較し、 diff を取る
    * diff が出た部分だけ本物の DOM に反映する
        * → 実装者は差分更新を気にする必要がないのが利点

### 配列の要素を表示するときには key 属性
* 下記のように配列の要素を map で繰り返し render するような処理がある場合

```js
// bad
render() {
  return this.props.recordList.map((record) => {
    return(
      <div className="xxx">
        record.name
      </div>
    );
  });
}
```

* 仮にこの recordList の長さが 5 あるとし、そのうち 1 つの要素に変更が入ったとしても
react は 5 つのうちどこに変更が入ったかわからない(要素のマッピングが出来ない)
    * せっかく Virtual DOM を採用しているのに差分チェックが遅くなってしまう…
* この問題を解決するために key 属性として unique な id を付与する手法が推奨される

```js
// good
render() {
  return this.props.recordList.map((record) => {
    return(
      <div className="xxx" key=record.id> // key を付与
        record.name
      </div>
    );
  });
}
```

* key 属性の付与を徹底することで Virtual DOM の利点を活かせる

**配列の要素を表示するときには気をつけたいこと**

* list! map! key!

## :four: 複数のフォーム要素のイベント処理について

* 単純にフォームを書くと、フォームの数だけイベントハンドラが必要になってしまう…
* そこでイベントハンドラに追加の引数を渡すことで、イベントハンドラの削減を検討する

```js
// bad
onChangeName(event) {
  const newState = {};
  newState.name = event.target.value;
  this.setState(newState);
}

onChangeAddress(event) {
  const newState = {};
  newState.address = event.target.value;
  this.setState(newState);
}

render() {
  return (
    <div className="xxx">
      <input
        type="text"
        value={this.state.name}
        onChange={(event) => this.onChangeName(event)}
      />
      <input
        type="text"
        value={this.state.address}
        onChange={(event) => this.onChangeAddress(event)}
      />
    </div>
  );
}
```

```js
// good
onChange(label, event) {
  const newState = {};
  newState[label] = event.target.value;
  this.setState(newState);
}

render() {
  return (
    <div className="xxx">
      <input
        type="text"
        value={this.state.name}
        onChange={(event) => this.onChange('name', event)}
      />
      <input
        type="text"
        value={this.state.address}
        onChange={(event) => this.onChange('address', event)}
      />
    </div>
  );
}
```

**フォーム作成で気をつけたいこと**

* イベントハンドラに追加の引数を！

-----

# おわりに

以上で [ACCESS Advent Calendar 2016](http://qiita.com/advent-calendar/2016/access) 終了します。購読いただいた方ありがとうございました。

それではみなさん、良いお年を！