【React初心者】react-motionでクリスマスなものを作りました

Qiita初めての投稿になります。rikoです。

普段はバックエンドがメインだったのですが、フロントエンド開発をやってみたいと思っていたところ、twitterで「React」というものを勧めて頂きまして、「create-react-app」から始めました。
１つ、小さいですが初めてreactでものが出来上がりましたので、そのことについて投稿しようと思います。

#作ったもの
今回、クリスマスツリーの飾りをクリックしたら動く、というだけのSPAを作ってみました。「react-motion」というライブラリーを使いましたので、ご紹介します。

□Christmas bell
https://riko0000.github.io/bell_pj/

###開発環境
- Windows10
- Google Chrome
- エディタはAtom

###作るためにインストールしたもの
- Node.js（Reactを初めて使うため）
- create-react-app
- react-motion
- gh-pages（github pagesへのデプロイ）

###ソースコード
以下のgithubページに置いています。
https://github.com/riko0000/bell_pj

#やったこと
###ベルのコンポーネント作成
```react:Bell.js
import React, { Component } from 'react';
import { Motion, spring } from 'react-motion';

export default class Bell extends Component {
  constructor(props){
    super(props);
    this.state = {sf: 0, dp: 0, circleX: this.props.x };
  }

  render(){
    return(
      <Motion
        defaultStyle ={{ cx : this.state.circleX }} style ={{ cx : spring((this.state.circleX + 15), {stiffness: this.state.sf, damping: this.state.dp}) }}>
        {interpolatingStyle =>
            <circle
            onMouseDown={this.onClickCircle.bind()}
            onMouseUp={this.onEndOfClick.bind()}
            onTouchStart={this.onClickCircle.bind()}
            onTouchEnd={this.onEndOfClick.bind()}
            cx = {interpolatingStyle.cx} cy={this.props.y} />
          }
      </Motion>
    )
  }

  onClickCircle = ()  => {
    this.setState({sf: 400, dp: 5 ,circleX: this.props.x});
  };

  onEndOfClick = ()  => {
    this.setState({sf: 400, dp: 5, circleX: this.props.x - 15});
  };
}
```
まずは、クリックすると揺れるベルのコンポーネントです。ここで、react-motionをimportしています。
svgの「circle」タグの横の位置を示す「cx」の値を、Motionで変更することにより動かしています。値を動かしているのは「spring」という関数です。
<Motion>タグの中で、defaultStyle～Styleへ徐々に変更されています。
spring関数の引数「damping」の値で、バウンド幅を設定できます。

###ベルの配置
```react:App.js.js
import React, { Component } from 'react';
import './App.css';
import Bell from './Bell.js';

class App extends Component {

  renderCircle(x,y){
    return <Bell x={x} y={y} />
  }
  render() {
    return (
      <div className="App" >
        <svg>
          {this.renderCircle(260,280)}
          {this.renderCircle(400,320)}
          {this.renderCircle(180,450)}
          {this.renderCircle(300,480)}
          {this.renderCircle(430,480)}
          {this.renderCircle(150,630)}
          {this.renderCircle(310,620)}
          {this.renderCircle(480,620)}
        </svg>
      </div>
    );
  }
}
export default App;
```
ここでは単純に、先ほど作ったBellを何個も呼んでいるだけです。
引数に、circleのcxとcyに繋がる値を設定し、配置位置を決めています。

単純な処理ですが、私はこれをどう実装すれば分からずかなり時間をかけてしまいました。
結果、チュートリアルの「Tic Tac Toe」の実装を参考にしたら実現できました。

###それ以外はほぼ変更せず実現
この２モジュール以外はcssなどを変更しただけで、あとはすべてcreate-react-appの時のままです。

#つまづいたところ
###MotionはdefaultStyleとStyleの値が同じでは動かなかった
今回やりたいのは、「クリックすると揺れる」だけなので、位置は変えたくありません。
Bell.jsの<Motion>タグ内で、最初はonClickイベントにして、defaultStyleとStyleを同じ値にしていたのですが、動きませんでした。
今回、MouseDownで一度位置をずらし、MouseUpで戻しています。

###MouseイベントとTouchイベント
これは、フロントエンドエンジニアなら基本だとは思うのですが、
私は初フロントエンドだったのでここを両方対応する方法が全くわかりませんでした。
今回、App.cssでcircleの「cursor」を「Pointer」にし、Bell.jsの<circle>タグ内に、Mouse系イベントとTouch系イベントを列挙したら動くようになりました。

上記２点については、良いやり方か分からないので、引き続き調べようと思います。

#まとめ
クリスマスにちなんだSPAでした。
よければ作って楽しんでみてくださいね。

#参考にさせていただいたサイト
https://qiita.com/takayuki-ochiai/items/7f83dd90bc46ce2f156c
https://qiita.com/yuitnnn/items/11375ea29ec023d19fdf