2018年08月

9

木曜日の投稿

玉置 喜宣
投稿者:玉置 喜宣
(コーダー)

2018年08月09日

できる!はじめてのReact 〜ES6〜 #1

コーダーのあーだこーだ

玉置 喜宣
投稿者:玉置 喜宣(コーダー)

はじめに

入社して一年も経たない新人ですが、ある日React(リアクト)を業務で使うことになりました。調べてみるとたくさん記事が出てくる出てくる…。ひょんなことから Web業界ではメジャーという React を使うことになったのです。実は JavaScript、jQuery も付け焼き刃程度で、マスターしたというのには程遠い状態でした(泣)。

そこで、経験が浅いながらも自分なりに理解してみようと思い、今回の記事でまとめてみることにしました。

Reactって何?

React(リアクト)とは

Reactとは、コンポーネントを作って並べるだけで実現できるJavaScriptライブラリであり、なんとFacebook・Instagramで全面的に採用されている技術なのです。今巷で話題のインスタも?!とちょっとした驚きとともに興味がもっと湧いてきました。

 

Reactの特徴

ではReactって具体的にどんな特徴があるのでしょうか。下記を見てみましょう。

はい。
JavaScriptっぽくないJavaScriptライブラリでコンポーネントというのを使うみたいですね。
便利そうなのは伝わってきました。
でもまだよく分かりません…。

 

Reactを理解する 5 つのキーワード

 

Reactには一体何を使うのでしょうか。登場人物を見てみましょう。


はい…。

便利そうですけど、耳慣れないキーワードが幾つも出てきて、そう簡単ではなさそうですね。
そんな時、私はいつも魔法の言葉を唱えます。

「案ずるより産むが易し」

どうやら React はコンポーネントというものを作って並べるようですね。
ひとまず使ってみて、実際に動かしてみながら一つ一つ理解してみましょう。

 

JSX(JavaScript XML)って何?

JSXは、JavaScript を HTML風に書くのに便利な言語拡張だそうです。
JSXを使わなくても React は使えます。しかし、JSXを使うことで Reactをより便利に使うことができるようになります。

具体的には、Reactを書くためのコードを HTML風に記述してコンポーネント作成することができるようになるので、ローディング後の HTMLをイメージしながら直感的にコーディングすることができるようになります。

React、その前に

ES6(ES2015)

JavaScriptを標準化するためのルールに基づいて作られた ECMAScript のバージョンを指します。
便利な機能が追加され、より簡単で分かりやすく記述できます。
ECMAScriptはES6(2015年6月公開)で画期的な進化を遂げたといってもよいでしょう。
ES6を使うしかないですね!!

しかし、IE11、Opera Mini、Samsung Internetなどのブラウザでは使えないんです!!(2018年7月13日現在)
そこで・・・Babel を使うんです。

 

Babelとは

ES6で追加された機能をES5に変換するNode.js製のトランスパイラ(コンパイラ)のこと
ES6をES5に変換してしまえばブラウザを意識しなくて済みます。

Babelを使えるようにするには

 コード内に下記を1行追加するだけ!!

<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.10.3/babel.min.js"></script>

※CDN(コンテンツデリバリーネットワーク。配信用ネットワークのこと)というサービスなのですが、今回のテーマではないので割愛します。

Reactを使う 〜コンポーネントを作ってみよう〜

今回はReactをスムーズに理解するために、環境構築も含めてできるだけシンプルで無駄のないものを作ることにしましょう!!
そこで、今回は「お買い物で購入する商品の計算をする画面」を作ることにします。

 


★完成イメージ
 

1、HTMLを用意

今回 React を作る際のフォルダ構成は下記になります。

root/
├ index.html
└ js/
   └ calculator.js

まず最初に、HTMLを見てみましょう。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>React Test</title>
  <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.10.3/babel.min.js"></script>
</head>
<body>
<h1>らくらくお買い物♪</h1>
<div id="area_calc"></div>
<script type="text/babel" src="/js/calculator.js"></script>
<script type="text/babel">
    /* 生成したコードを#area_calcに出力 */
    ReactDOM.render(
        <MyCalc name="メロン" price={540} />,
        document.getElementById('area_calc')
    );
</script>
</body>
</html>

<head>タグから見ていきましょう。下記のように必要なものを読み込んでいます。

Reactの読み込み
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
Babelの読み込み
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.10.3/babel.min.js"></script>

前述しましたが、これだけでReactとBabelが使えるようになります。

次に、<body>タグの中を見てみましょう。

これから作る React コンポーネントの HTML が出力される場所を定義
<div id="area_calc"></div>

作った React を出す場所としてdiv タグに任意のidをつけて用意しておきます。

これから作るReactコンポーネント MyCalc を記述した JavaScript ファイル「calculator.js」の読み込みと、コンポーネントの出力
<script type="text/babel" src="/js/calculator.js"></script>        ・・・#1
<script type="text/babel">                                                        ・・・#2
    /* 生成したコードを#area_calcに出力 */
    ReactDOM.render(                                                               ・・・#3
        <MyCalc name="メロン" price={540} />,                          ・・・#4
        document.getElementById('area_calc')                             ・・・#5
    );
</script>

#1では、これからコンポーネントを定義する JavaScript を読み込んでいます。

#2〜5では、#1で定義したコンポーネントを使って HTML にレンダリング(描画)を行なっています。

#3は実際に HTML にレンダリングするための React のメソッドになります。

#4では、後で実際に作る MyCalc コンポーネントというものについてnameに「メロン」、priceに「540」というパラメータを渡しています。

#5では、このHTMLの「area_calc」というIDをもつ箇所に出力しますよーと指定しています。

#1,2について、ここで一点注意していただきたいのは、「type="text/babel"」と記述することです。
これを記述しないとこれから ES6 で作成する React のコードを JavaScript に変換(トランスパイル)してくれません。
ここはこれだけでは何なのか今は分かりづらいので、分からなくても一旦読み進めましょう。後で説明します。

2、JavaScriptの記述

次に、JavaScriptを見てみましょう。

calculator.js
class MyCalc extends React.Component {
 
    constructor(props) {
        super(props);
 
        this.state = {
            item_quantity: 0,
            item_amount: 0
        }
 
        // ES6は明示的にbindしてあげる必要がある
        this.setQuantity = this.setQuantity.bind(this);
        this.calcMultiple = this.calcMultiple.bind(this);
    }
 
    setQuantity =(event)=> {
        this.setState({
            item_quantity: event.target.value
        });
    }
 
    calcMultiple =()=> {
        let amount = this.props.price * this.state.item_quantity;
        this.setState({
            item_amount: amount
        });
    }
 
    render() {
        return (
            <p>
                <span>{this.props.name} : {this.props.price}円 x </span>
                <input type="text" name="count" onChange={this.setQuantity}/>個
                <button onClick={this.calcMultiple}> 【計算する】 </button>
                <span>{this.state.item_amount}</span>円
            </p>
        );
    }
}

1.コンポーネントの定義

はい、ここでようやくコンポーネントを作るんですね!

Reactコンポーネント「MyCalc」の定義
class MyCalc extends React.Component {
 〜中略〜
}

MyCalcという名前でHTMLにレンダリング(描画)するReactコンポーネントの記述になります。
MyCalcコンポーネントの中を一つ一つ見ていきましょう!

レンダリング用のrender()メソッド
render() {
    return (                                                                                                ・・・#6
        <p>                                                                                                  ・・・#7
            <span>{this.props.name} : {this.props.price}円 x </span>          ・・・#8
            <input type="text" name="count" onChange={this.setQuantity}/>個          ・・・#9
            <button onClick={this.calcMultiple}> 【計算する】 </button>          ・・・#10
            <span>{this.state.item_amount}</span>円          ・・・#11
        </p>
    );
}

#6では、この MyCalc コンポーネントが実際に HTML にレンダリングを行うときの処理(内容)を return にて返しています。

#7〜11は、どこかでみたことがありますね。これが JSX です。HTML みたいです。
見慣れないタグはありませんね(正確にはタグではなく Virtual DOM です)

#7について、これは HTML にそのまま <p> タグとしてレンダリングされます。

#8も#7同様 <span> タグとして出力されますが、見慣れない「this.props.name」や「this.props.price」がありますね。

はい、ここで index.html の #4 を思い出して見ましょう!
これは、

・this.props.name     ・・・・・前述の#4で指定したnameの値
・this.props.price    ・・・・・前述の#4で指定したpriceの値

になります。
これが「プロパティ」です。
「Reactを理解する 5 つのキーワード」でご紹介した”コンポーネントに外部から与えられる値”ですね。
これで「メロン」や「540」などの値を <span> タグ内に表現することができるのです。

#9について、<input> タグの一般的な type や name などがありますね。こちらは説明不要ですね。
しかし、こちらも見慣れない「onChange={this.setQuantity}」があります。
これはinputタグに数値の入力や削除など何か変更を加える度に自分自身のコンポーネント内に定義した setQuantity()メソッドを呼び出します。

#10についても、<button>タグとなっていて見慣れない「onClick={this.calcMultiple}」があります。
こちらも#10同様に、<button>でレンダリングされたHTML上のパーツをクリックすると自分自身のコンポーネント内に定義したcalcMutiple()メソッドを呼び出します。

#9,#10のsetQuantity()メソッドとcalcMultiple()メソッドについては後ほどご説明します。

#11について、<span>タグなのはわかりますが、またまた見慣れない「{this.state.item_amount}」が出てきました。
どこかで定義した値を表示しているように見えます。
よく見ると「state」とありますね。
これが「ステート」です。
「Reactを理解する 5 つのキーワード」でご紹介した”コンポーネントの状態変化を保持するために使用する値”ですね。
計算結果を出力する箇所であり、React によって瞬時に動的に書き換えを行う箇所のため、プロパティではなくステートを使う必要があるのです。

ステートを使うためにはどうすればよいのでしょうか。
MyCalcコンポーネントの constructor()メソッドを見てみましょう。

constructor(props) {                                          ・・・#12
    super(props);                                             ・・・#13
    this.state = {                                            ・・・#14
        item_quantity: 0,
        item_amount: 0
    }
 
    this.setQuantity = this.setQuantity.bind(this);                 ・・・#15
    this.calcMultiple = this.calcMultiple.bind(this);         ・・・#16
}

まずはじめに、ステートは”コンポーネントの状態変化を保持するために使用する値”ですが、コンポーネントの外部から直接変更することはできません。

ではどうやって書き換えるのかを見てみましょう。

ステートが書き換えられる値ということは最初に何らかの値を持っている必要があります。
前述の「今回作るもの」の完成イメージをみていただくと分かりますが、未入力の場合は「0」が表示されています。
つまり画面表示時は無条件に「0」と表示されるようにしておく必要があります。

#12について、これはこのコンポーネントが呼び出された時に一番最初に実施される constructor()メソッドになります。

#13は、プロパティを使用できるようにするためのものです。

#14について、これがステートの定義箇所になります。そして constructor()メソッド内なので初期化を意味します。
#14では、「item_quantity」と「item_amount」をそれぞれ「0」で初期化しています。

ここまでで、ひとまずステートを使うことができるような手続きは終わりました。
しかし、「どうやってステートを書き換えているの?」という疑問が残りますよね!
思い出してみましょう。
先ほど#9,10にて「setQuantity()メソッドとcalcMultiple()メソッドについては後ほどご説明します。」とお伝えしました。
実は#9,10でステートを書き換えてます!

それでは早速それぞれ見ていきます。
まずsetQuantity()メソッドについて見てみましょう。
こちらは「onChange={this.setQuantity}」で呼び出していましたね!

setQuantity =(event)=> {
    this.setState({
        item_quantity: event.target.value
    });
}

つまり、何か数字を入力する度にイベントがsetQuantity()メソッドに渡され、受け取ったイベントから入力された値を自身のコンポーネントで先ほど初期化したitem_quentityにセットしています。
これがステートの書き換えなんです。

次にcalcMultiple()メソッドについて見てみましょう。
こちらは「onClick={this.calcMultiple}」で呼び出していましたね。

calcMultiple =()=> {
    let amount = this.props.price * this.state.item_quantity;
    this.setState({
        item_amount: amount
    });
}

こちらもsetCount同様、クリックする度に calcMultiple()メソッドが呼び出され、プロパティで受け取った priceと、ステート「item_quantity」の現時点での値を掛け算し、その結果を自身のコンポーネントで先ほど初期化した item_amount にセットしています。
こちらもステートの書き換えを行なっています。

今までの作業を整理してみましょう。
MyCalcコンポーネントにて、HTMLのReactDOM.render()メソッドから受け取った「メロン」「540」などの値をプロパティとして、また入力欄と出力欄に事前に初期値をステートとして定義し、それらの値を使用してHTML風(JSX)にしてDOM構造を生成します。
しかし、これはHTMLではなく「Virtual DOM」になります。
React はこの Virtual DOM を実際の HTML に変換して画面に出力します。
入力欄への入力やボタンの押下によって setQuantity()メソッドや calcMultiple()メソッドを呼び出してステートを書き換えることによって、画面遷移なく画面の表示内容が変わります。
このとき、DOMを最初から作り直すのではなく、Virtual DOM の変更差分だけを修正して DOM に反映するために React が速いのです!!

しかし、実はこれだけでは動きません。
お気づきでしょうか。#15,16の話をしていませんね。
実は#15,16のように constructor()メソッド内で事前に各メソッドに bindしてあげないと各メソッドは動作しないのです。

this.setQuantity = this.setQuantity.bind(this);
this.calcMultiple = this.calcMultiple.bind(this);

ここは意外につまづくポイントとなりがちなので気をつけましょう!

3、JavaScriptのHTMLでの記述(HTMLへの出力)

改めて、HTMLへの出力箇所を見てみましょう。

作ったReactコンポーネントを用いてHTML内に出力
<script type="text/babel" src="/js/calculator.js"></script>        ・・・#1
<script type="text/babel">                                                        ・・・#2
    /* 生成したコードを#area_calcに出力 */
    ReactDOM.render(                                                               ・・・#3
        <MyCalc name="メロン" price={540} />,                          ・・・#4
        document.getElementById('area_calc')                             ・・・#5
    );
</script>

#1で、これからコンポーネントを定義するJavaScriptを読み込んで、

#4で、作ったMyCalcコンポーネントのnameに「メロン」、priceに「540」というパラメータを渡してMyCalcコンポーネントを呼び出し、

#5で、このHTMLの「area_calc」というIDをもつ箇所に出力しますよーと指定し、

#3で、実際にHTMLにレンダリングします。

4、コンポーネントの複製

最後に、コンポーネントの複製の話をしましょう。

index.html内のJavaScript記述部分
<script type="text/babel">
    /* 生成したコードを#area_calcに出力 */
    ReactDOM.render(
        <div>                                                                              ・・・#️17 
            <MyCalc name="メロン" price={540} />
            <MyCalc name="いちご" price={500} />
            <MyCalc name="バナナ" price={440} />
        </div>,
        document.getElementById('area_calc')
    );
</script>

先ほどの#4について、作成した MyCalcコンポーネントを上記のように同じパラメータ形式で値だけ変更することによって、同じ見た目、同じ挙動のモジュールを幾つも作ることができます!
作るのはちょっと大変でしたが、一旦作ってしまえば後は楽ですよね!

#17の<div>はマークアップ的に無くてもいいのでは?とお思いになった方もおられるかもしれません。
しかし、React ではレンダリング内容をreturnする時のDOM構造の最上層は一つでないといけないという決まりがあります。
そのため、複数の並列要素を返したい時は外側を<div>タグなどでラッピングする必要があります。
これで、Reactコンポーネントが完成です!!
不要な画面遷移もしません。


★完成イメージ

今回のように軽量なものであればさほどReactの威力は発揮できないため、Reactを使わなくても差異はないでしょう。
しかし、より複雑なモジュールや膨大なデータを取り扱うときには一層威力を発揮してくれることでしょう!

おまけ

「React Developer Tools」
https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi

Google Chromeのアドオン。Reactでレンダリング(描画)された画面でどのようにコンポーネントが使用されているかを確認したい!そんな方にオススメです。

 

この投稿を書いた人

玉置 喜宣

玉置 喜宣(たまき よしのり)コーダー

コーディングファクトリー部コーダー。看護師からSE、そしてフロントエンドという異色の経歴を持つが、それはやりたいことを探し求めてきた結果。食べることが大好きですが、食べると眠くなって戦どころではないのが悩みどころ…。

玉置 喜宣が書いた他の記事を見る