Skip to content
This repository has been archived by the owner on Nov 12, 2019. It is now read-only.
takanorip edited this page Aug 6, 2016 · 4 revisions

#ハンズオン概要

HTML

今回はHTMLファイルはほとんど編集しません。
react-like-button/index.htmlを下記のように編集します。

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>React App</title>
  </head>
  <body>
    <h1>Reactハンズオン</h1>
    <div id="root"></div>
  </body>
</html>

今回はid="root"にコンポーネントが出力されます。

CSS

CSSはreact-like-button/src/App.cssを編集します。 今回のCSSは下記リンクにあるデザインを参考にしました。 http://stackoverflow.com/questions/23333010/how-to-draw-the-of-likes-bubble-like-what-is-on-the-right-side-of-the-facebook

.container {
  font-family: helvetica, arial, 'hiragino kaku gothic pro', meiryo, 'ms pgothic', sans-serif;
  font-size: 11px;
}
.like {
  display: inline-block;
  background: #3b5998;
  padding: 0px 5px;
  border-radius: 2px;
  color: #ffffff;
  cursor: pointer;
  float: left;
  height: 20px;
  line-height: 20px;
}
.likeHover {
  background: #444;
}
.counterBefore {
  display: block;
  float: left;
  width: 6px;
  height: 6px;
  background: #fafafa;
  margin-left: -12px;
  border-right: 10px;
  transform: rotate(45deg);
  -webkit-transform: rotate(45deg);
  margin-top: 6px;
  border-left: 1px solid #aaa;
  border-bottom: 1px solid #aaa;
}
.counter {
  display: block;
  background: #fafafa;
  box-sizing: border-box;
  border: 1px solid #aaa;
  float: left;
  padding: 0px 8px;
  border-radius: 2px;
  margin-left: 8px;
  height: 20px;
  line-height: 20px;
}

##React

今回のメインであるReactを書いていきます。 react-like-button/src/App.jsを編集します。

骨組み

まず一番外の枠を書いていきます。 最初にReactとCSSを読み込みます。importというのはES2015で外部モジュールを読み込むときに使います。

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

//Componentを継承
class App extends Component {

  //props, stateを記述
  constructor(props) {
    super(props);
  }

  //コンポーネントとして出力される部分
  render() {
    return (
      <span className="container">いいねボタン</span>
    );
  }
}

//モジュール化
export default App;

ホバーした時の色を変える。

続いて、ホバーした時の色を変えます。CSSでホバーしても良いのですが、今回はホバーしたらクラスを変化させ、色を変えたいと思います。

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

class App extends Component {
  constructor(props) {
    super(props);
    // ホバーしているかどうかの状態をstateとして保持
    this.state = {
      hovered: false,
    }
  }

  // ホバー時に状態を変化させるイベントハンドラ
  onMouseEnter() {
    this.setState({hovered: true});
  }

  // カーソルが降りた時に状態を変化させるイベントハンドラ
  onMouseLeave() {
    this.setState({hovered: false});
  }

  render() {
    //stateの値によってclassNameを変更
    const likeClass = this.state.hovered ? "like likeHover" : "like";

    console.log(this.state); // 状態をログに出す

    // ボタンに onMouseEnter と onMouseLeave のイベントハンドラをbind
    return (
      <span className="container">
        <span
          onMouseEnter={this.onMouseEnter.bind(this)}
          onMouseLeave={this.onMouseLeave.bind(this)}
          className={likeClass}>いいね!</span>
        <span className="counter">
          <span className="counterBefore">{" "}</span>
          999
        </span>
      </span>
    );
  }
}

export default App;

クリックできるようにする

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

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      hovered: false,
      //状態を追加
      count: 999,   //カウンターの数
      liked: false  //クリックしたかどうか
    }
  }

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

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

  //クリック時に状態を変化させるイベントハンドラ
  onClick(){
    this.setState({

      //クリック時にcountの状態がfalseだったら+1、trueだったら-1
      count: this.state.count + (this.state.liked ? -1 : 1),

      //likedの状態を反対にする(false → true, true → false)
      liked: !this.state.liked
    });
  }

  render() {
    const likeClass = this.state.hovered ? "like likeHover" : "like";

    return (
      <span className="container">
        <span
          onMouseEnter={this.onMouseEnter.bind(this)}
          onMouseLeave={this.onMouseLeave.bind(this)}

          //クリックにイベントハンドラをbind
          onClick={this.onClick.bind(this)}

          //likedがtrueだったら"✔"を追加
          className={likeClass}>{this.state.liked ? "✔" : ""}いいね!</span>
        <span className="counter">
          <span className="counterBefore">{" "}</span>

          //カウンターの数を表示
          {this.state.count}
        </span>
      </span>
    );
  }
}

export default App;

###出力

ReactではReactDOM.render()を使ってコンポーネントを出力します。今回はindex.jsに処理が書いてあります。

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';  //Appモジュールを読み込み
import './index.css';

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

##完成

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

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      hovered: false,
      count: 999,
      liked: false
    }
  }

  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 likeClass = this.state.hovered ? "like likeHover" : "like";

    return (
      <span className="container">
        <span
          onMouseEnter={this.onMouseEnter.bind(this)}
          onMouseLeave={this.onMouseLeave.bind(this)}
          onClick={this.onClick.bind(this)}
          className={likeClass}>{this.state.liked ? "✔" : ""}いいね!</span>
        <span className="counter">
          <span className="counterBefore">{" "}</span>
          {this.state.count}
        </span>
      </span>
    );
  }
}

export default App;
Clone this wiki locally