30分間React入門「いいねボタン」作成チュートリアル!
「今日からReactを始めたい」
「とりあえずReactで何か動かしてみたい」
ここは、そういった方が、Reactを始めみるためのチュートリアルです。
今回は、Reactを使ってFacebookのいいねボタンのようなコンポーネントを実装していきます。
> 今回作る「いいねボタン」のデモ今回作る「いいねボタン」のデモ
実際に押せます↓
> チュートリアルの目標チュートリアルの目標
- Reactのコンポーネントを実装できるようになる
- Reactコンポーネントのイベントをハンドリングできるようになる
- Reactコンポーネントの状態(state)を実装できるようになる
- Reactの雰囲気をつかめる!
> このチュートリアルについてこのチュートリアルについて
なお、このチュートリアルは、下記のバージョンで動作確認しています。
- npm 2.14.2
- react 0.14
- react-dom 0.14
- webpack 1.12.2
- babel-core 5.8.25
- babel-loader 5.3.2
このチュートリアルで作成するコンポーネントの完成形はGitHubからチェックアウトできます。
また、今回はReactだけでコンポーネントを作成し、Fluxは使用しません。
> 下準備下準備
> 下準備__colon__ プロジェクト新規作成下準備: プロジェクト新規作成
ひとまずディレクトリを作って、
mkdir react-like-button
cd react-like-button
プロジェクトを初期化します。
npm init
> 下準備__colon__ 必要ツールのインストール下準備: 必要ツールのインストール
開発に必要なツールをnpmでインストールしておきます。
npm install --save-dev webpack babel-loader
今回インストールするのは次の2つです。
- webpack: JSを依存関係を解決しつつ、ひとつのスクリプトにビルドしてくれるツール。
- babel-loader: ES6、ES7のトランスパイラBabelをwebpackで使えるようにするアドオン。
これらのツールの説明は省略します。詳しくは次の記事をご参考に。
> 下準備__colon__ webpackの設定下準備: webpackの設定
webpack.config.js
という名前でwebpackの設定ファイルを作ります。
touch webpack.config.js
module.exports = {
entry: __dirname + "/src/main.js",
output: {
path: __dirname + "/dist",
filename: "like-button.js"
},
module: {
loaders: [
{test: /\.js$/, loader: "babel-loader?stage=0"}
]
}
};
少し説明すると、entry
とoutput
では「src/main.js
をコンパイルし、dist/like-button.js
を生成する」設定になっています。loaders
は拡張子がjsのものにbabel-loaderを適用する設定、つまりES6をJSに変換するようになっています。stage=0
はES7も有効にするBabelの設定です。
ソースコード置き場と、ビルドされたJSが生成される場所を作ります。
mkdir src dist
> 下準備__colon__ コンポーネントを実装するファイルを作る下準備: コンポーネントを実装するファイルを作る
まずは、ボタンをコーディングするファイルを作りましょう。
touch ./src/main.js
webpackでちゃんとビルドされるかを確認したいので、ひとまず、中身はconsole.log
にしておき、読み込まれていることが確認できるようにしておきます。
console.log("OK");
> 下準備__colon__ 確認用ページを作る下準備: 確認用ページを作る
つぎに、ビルドされたJSの動作確認をするHTMLを作ります。
touch dist/index.html
中身はこんなかんじ。
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Reactで作った「いいねボタン」のデモ (Flux不使用)</title>
</head>
<body>
<h1>Reactで作った「いいねボタン」のデモ (Flux不使用)</h1>
<script src="like-button.js"></script>
</body>
</html>
> 下準備__colon__ webpackでビルドを試す下準備: webpackでビルドを試す
ビルドするために、package.json
にwebpackのビルドタスクを定義しておきます。
{
...
"scripts": {
...
"build": "rm -rf dist/*.js && webpack",
"watch": "rm -rf dist/*.js && webpack -w"
},
...
}
ひとつ目は単発でビルドするタスクの定義、ふたつ目はソースコードが変更されたら自動でビルドが走るタスクです。
開発時はふたつ目を使います。
ビルドタスクが走るか試してみましょう。
npm run build
dist/like-button.jsが生成されたでしょうか?
最後に、確認ページを開き、コンソールに「OK」と出ているのが確認できれば、ビルドも実行もうまくいったことになります。
open dist/index.html
下準備は以上です。
> 「いいね!」ボタンを作る「いいね!」ボタンを作る
ここからは「いいね!」ボタンの開発に入っていきます。
> ReactをインストールReactをインストール
Reactをインストールします。
npm install --save react react-dom
確認用HTMLdist/index.html
を変更して、Reactコンポーネントをマウントする場所をHTMLに書き込みます。
...
<h1>Reactで作った「いいねボタン」のデモ (Flux不使用)</h1>
<div id="like-button"></div><!-- ここにコンポーネントをマウント -->
<script src="like-button.js"></script>
...
like-button.js
が読み込まれると、このid="like-button"
にいいねボタン コンポーネントが描画されます。
まずは、最もシンプルなコンポーネントをmain.js
に書いてみましょう。<span>
を出力するだけのコンポーネントです。
import React from "react";
import ReactDom from "react-dom";
class LikeButton extends React.Component {
render() {
return (
<span>いいねボタン予定地</span>
);
}
}
ReactDom.render(
<LikeButton />,
document.getElementById("like-button")
);
コードに直接書かれた<span>
タグなどはJSXと呼ばれます。HTMLに見えますがXMLです。XMLなので閉じタグを省略できない点に注意してください。React.Component
を継承し、render
メソッドを実装すると、Reactコンポーネントになります。Reactコンポーネントは、クラス名をそのままJSXのタグに使うことができます。
HTMLとJSXの違いについてはドキュメントに説明があります。
webpackのwatchタスクを起動して、ビルドを走らせます。
npm run watch
ビルドが終わったら、確認用HTMLを読み込みしなおしてみて、「いいねボタン予定地」が表示されていればOKです。
> ボタンのデザインを作りこむボタンのデザインを作りこむ
「いいね!」ボタンはFacebookのLikeボタンのようにボタンと吹き出しがセットのものを作ります。
このチュートリアルでは、Facebook風のデザインを作る上で、html - how to draw the # of likes bubble like what is on the right side of the facebook like button - Stack Overflowを参考にしています。
先ほどのLikeButton
の中身を書き換えて、JSXとスタイルを書きます。
class LikeButton extends React.Component {
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"
}
};
}
render() {
const styles = this.styles();
return (
<span style={styles.container}>
<span style={styles.like}>いいね!</span>
<span style={styles.counter}>
<span style={styles.counterBefore}>{" "}</span>999
</span>
</span>
);
}
}
ReactではclassName
属性を使えばスタイルシートをCSSに追い出すこともできますが、
ウィジェットとして設置可能にすることまで考えて、ここではインラインスタイルで書きます。Reactのインラインスタイルは、JavaScriptのオブジェクトで表現する点が、普通のHTMLとは異なります。
> カーソルが乗った時にボタンの色を変えるカーソルが乗った時にボタンの色を変える
いいねボタンにカーソルが乗った時に、背景色が変化するフィードバックを実装します。
CSSであれば:hover
を定義するだけですが、Reactのインラインスタイルでは、onMouseEnter
イベントとonMouseLeave
を使って動的にスタイルを変更する方法で実装します。
今のLikeButton
コンポーネントに手を加えて、カーソルが乗っているかの状態とイベントハンドラを追加します。
class LikeButton extends React.Component {
constructor(props) {
super(props);
// コンポーネントにカーソルが乗ているかどうかの状態を持たせる
this.state = {
hovered: false
}
}
styles() { ... }
// カーソルが乗った時に状態を変更するイベントハンドラ
onMouseEnter() {
this.setState({hovered: true});
}
// カーソルが外れた時に状態を変更するイベントハンドラ
onMouseLeave() {
this.setState({hovered: false});
}
render() {
const styles = this.styles();
console.log(this.state); // 状態をログに出す
// ボタンに onMouseEnter と onMouseLeave のイベントハンドラを割り当てます
return (
<span style={styles.container}>
<span
style={styles.like}
onMouseEnter={::this.onMouseEnter}
onMouseLeave={::this.onMouseLeave}>いいね!</span>
<span style={styles.counter}>
<span style={styles.counterBefore}>{" "}</span>999
</span>
</span>
);
}
}
ビルドが走ったら、確認用HTMLにて、ボタンにカーソルを乗せたり外したりしてみて、
コンソールにコンポーネントの状態を出ているか確認してください。
ここまでできたら、this.state.hovered
の状態に応じてスタイルを切り替えれば、背景色を変更できます。render
メソッドを変更してみましょう。
class LikeButton extends React.Component {
...
render() {
const styles = this.styles();
// 状態に応じてスタイルを変更する
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}>いいね!</span>
<span style={styles.counter}>
<span style={styles.counterBefore}>{" "}</span>999
</span>
</span>
);
}
}
ちなみに、{...styles.like, ...styles.likeHover}
はES7でふたつのオブジェクトをマージする構文です。
色が変わるようになったでしょうか?
> ボタンを押して、数を増やしたり減らせるようにするボタンを押して、数を増やしたり減らせるようにする
最後に、ボタンを押したときに、数を増減する処理を追加します。
FacebookのLikeボタンに習い、次の仕様を実装します。
- いいね済みの場合: ボタンを押すといいね解除、カウンタを-1する。
- いいねがまだの場合: ボタンを押すといいね状態になり、カウンタを+1する。
カウント数と押したかどうかの2つの状態を、state
に追加します。
そして、クリックしたときのイベントハンドラと追加し、
そのイベントハンドラをボタンと紐付けます。
import React from "react";
import ReactDom from "react-dom";
class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = {
hovered: false,
count: 999, // カウント数の状態を追加
liked: false // 押したかどうかの状態を追加
}
}
styles() { ... }
onMouseEnter() { ... }
onMouseLeave() { ... }
// クリックしたときのイベントハンドラ
onClick() {
this.setState({
count: this.state.count + (this.state.liked ? -1 : 1),
liked: !this.state.liked
});
}
render() {
...
// this.state.likedとthis.state.countを追加し、
// onClickイベントハンドラを紐付ける
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>
);
}
}
この変更で、ボタンを押した時に、いいね数が変化するようになったかと思います。
> おわりおわり
以上で「いいね!」ボタンをReactで作るチュートリアルはおしまいです。
このチュートリアルで作成したコンポーネントの完全版はGitHubのsuin/react-like-button-exampleにて確認できます。
次は、もっと複雑なコンポーネントを実装するチュートリアルを紹介したいと思います!
質問や分からないことがあれば、お気軽にコメントしてください(^-^)