Reactでいいねボタン

どなたかが書かれていた気もしますが、[30分間React入門「いいねボタン」作成チュートリアル](http://c16e.com/1510161700/)というものを勉強がてら写経してみました。
途中、いくつかつまづいたとこもあったので備忘録として書きたいと思います。

途中に補足のようなことが書いてありますが、自分でもよくわかっていないので間違っていることなどあればご指摘いただけると助かります。
(ここに書いてあることはほとんど30分間React入門「いいねボタン」作成チュートリアルに書いてありますのでまずはそちらを御覧ください。)
#導入

まずはいろいろインストールしていきます。
本家では`babel-core`がインストールされておらずエラーが出ていたので忘れずにインストールしましょう。

```
$ npm init
$ npm install --save-dev webpack babel-loader babel-core
$ touch webpack.config.js
```


<dl>
<dt>webpack</dt>
<dd>Webアプリに必要なリソースの依存関係を解決してくれるビルドツールです。Reactを使うには必須のアイテムです。似たツールにBrowserifyなどがあります。JavaScriptだけでなく、CSS系（Sass, LESS, stylus）、画像ファイルなども扱うことができます。</dd>
<dt>babel</dt>
<dd>ECMAScriptコンパイラです。ECMAScript2015(ES6)やECMAScript2016(ES7)などをブラウザがサポートしているES5形式に出力してくれます。</dd>
</dl>

詳しい解説は下記リンクからどうぞ。

- [Babelで始める！モダンJavaScript開発](https://html5experts.jp/kyo_ago/16979/)
- [webpack で始めるイマドキのフロントエンド開発](http://qiita.com/yosisa/items/61cfd3ede598e194813b)


続いてwebpackの設定を記述していきます。
これも本家では古い書き方になっていてECMAScript2015だとエラーが出るので書き直しました。

参考：[webpack+babel環境でフロントエンドもES6開発](http://qiita.com/HayneRyo/items/74892d3a37ee96a5df60)

```javascript:webpack.config.js
module.exports = {
    entry: __dirname + "/src/main.js",
    output: {
        path: __dirname + "/dist",
        filename: "like-button.js"
    },
    module: {
        loaders: [{
            test: /\.js$/,
            loader: "babel",
            query: {
                presets: ["react", "es2015", "stage-0"] //react入れないとエラー出るよ&書き方がES2015だと違うよ
            }
        }]

    }
};
```

ソースコードとビルドされたJSが入るディレクトリを作成します。

```
$ mkdir src dist
$ touch ./src/main.js
$ touch dist/index.html
```

package.jsonにwebpackのビルドタスクを定義します。

```
{
...
  "scripts": {
    ...
    "build": "rm -rf dist/*.js && webpack",
    "watch": "rm -rf dist/*.js && webpack -w"
  },
...
}
```

Reactインストール

```
npm install --save react react-dom
```

#HTML
まず、骨組みとなるHTMLをdist配下に作ります。

```html:index.html
<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
  <title>デモ</title>
  <script src="like-button.js"></script>
</head>
<body>
  <div id="like-button"></div>
</body>
</html>
```

#React

メインのReactを書いていきます。

今回、CSSはReactの中にオブジェクトのような感じで書いていきます。
巷では[CSS in JS](http://postd.cc/modular-css-with-react/)とか言われており、新しいアプローチとして注目を浴びてるらしいです。


```javascript:main.js
import React from "react";
import ReactDom from "react-dom";

//コンポーネント定義

class LikeButton extends React.Component {
  constructor(props) {
    super(props);

//ホバーの状態、カウント数、Likeの有無をstateで定義

    this.state = {
      hovered: false,
      count: 999,
      liked: false
    }
  }
  styles() {
    return {
      container: {
        fontFamily: "helvetica, arial, 'hiragino kaku gothic pro', meiryo, 'ms pgothic', sans-serif",
        fontSize: 11
      },
      like: {
        display: "inline-block",
        background: "#3b5998",
        padding: "0px 5px",
        borderRadius: 2,
        color: "#ffffff",
        cursor: "pointer",
        float: "left",
        height: 20,
        lineHeight: "20px"
      },
      likeHover: {
        background: "#444"
      },
      counterBefore: {
        display: "block",
        float: "left",
        width: 6,
        height: 6,
        background: "#fafafa",
        marginLeft: "-12px",
        borderRight: 10,
        transform: "rotate(45deg)",
        WebkitTransform: "rotate(45deg)",
        marginTop: 6,
        borderLeft: "1px solid #aaa",
        borderBottom: "1px solid #aaa"
      },
      counter: {
        display: "block",
        background: "#fafafa",
        boxSizing: "border-box",
        border: "1px solid #aaa",
        float: "left",
        padding: "0px 8px",
        borderRadius: 2,
        marginLeft: 8,
        height: 20,
        lineHeight: "20px"
      }
    };
  }

//マウスホバーのイベントハンドラ

  onMouseEnter() {
    this.setState({hovered: true});
  }

  onMouseLeave() {
    this.setState({hovered: false});
  }

//クリックのイベントハンドラ

  onClick(){
    this.setState({
      count: this.state.count + (this.state.liked ? -1 : 1),
      liked: !this.state.liked
    });
  }

  render() {
    const styles = this.styles();

//ホバーの判定からのスタイル変更
//{...styles.like, ...styles.likeHover}はES7でふたつのオブジェクトをマージする構文

    const likeStyle = this.state.hovered ? {...styles.like, ...styles.likeHover} : styles.like;
    
    return (
      <span style={styles.container}>
        <span
          style={likeStyle}
          onMouseEnter={::this.onMouseEnter}
          onMouseLeave={::this.onMouseLeave}
          onClick={::this.onClick}>{this.state.liked ? "✔" : ""}いいね！</span>
        <span style={styles.counter}>
          <span style={styles.counterBefore}>{" "}</span>
          {this.state.count}
        </span>
      </span>
    );
  }
}

ReactDom.render(
  <LikeButton / >, document.getElementById("like-button"));
```


#おわりに
Reactを最近やり始めて、なんとなくコンポーネントのことやstate, propsのことがわかってきた気がします。
CSSをJSの中に書くのは初めてだったけど、Reactと一緒に使うと動的にCSSを適用することができて非常に便利だと感じました。