JavaScript
ECMAScript6
React

(イマドキの)手探りReact.js入門記

手探りVue.js入門記もどうそ。
同じようにノートとして使いつつ色々まとめていきます。追記予定。

自分以外の見る人へ

何番煎じの入門記事なんだと思う方もいるかもしれませんが、当記事では古今東西すべてのインターネット上のReact.jsのコードを今風に脳内で変換できるようになるまでに必要だった情報を重点的にまとめています。React.jsは今と昔で全然書き方が違うばかりか、何も考えず今風の書き方に脳内変換すると動かなかったりします。

ここのコードは下記のような環境で書かれています。

  • 記述にはVisualStudio Codeを使用
  • React.js / React-DOM.js / JSXTranceFormer.js Babel.js はCDNから取得(npm install等は使っていない)

要は一番手軽なReact.jsの始め方になります。

より詳しい入門記事を紹介

では。

実際に始める前に

React.jsを試すのにnpmで環境構築や雛形の生成はしたくない。その為CDNを使用することにした。
すでにここからReact.jsのバージョンによる差異が出てきている。

昔: 読み込むべきはReact.jsとJSXTranceFormer.js
今: 読み込むべきはReact.jsとReactDOM.jsBabel.js

React.js
=> 言わずもがな、React.js本体。必須。
ReactDOM.js
=> React.js 0.1.14~ はDOM操作に関する部分は分割された。クライアントサイドで描写するなら必須。
Babel.js
=> React.jsで利用されているHTMLの記法JSXを、内部的にJavaScriptに変換するために必須。
=> 以前はこの役割をJSXTranceFormer.jsが請け負っていた。HTML内のコメントを参照。

index.html
<!DOCTYPE html>
<html>
<head>
  <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-core/5.8.34/browser.min.js"></script>
</head>
<body>
  <div id="main"></div>
  <!-- 古いコードでは下記typeの部分が"text/jsx"になっている -->
  <script type="text/babel" src="js/script.js"></script>
</body>

今後のJavaScriptコードはすべてこのHTMLを使用している。

React.jsについて

先日はVue.jsを試したが、本当にやりたいのはReact.jsだったので手をつけ始める。
React.jsはVue.jsとは違い、HTMLの表現に"JSX"を使っているのが大きな特徴で、それ以外は素のJavaScriptのような見た目をしている。今回はReact.jsそのもののメリットやデメリットについては触れない。

react_sample.js
// 今風の書き方。下で解説。ちなみにこのclass一塊をReact.jsではコンポーネントと言う。
class Hello extends React.Component {
    render() {
        // JSXでレンダリングすべき要素を返す。
        return (<h1>Hello React.js</h1>);
    }
}
// 実際にレンダリングする部分。Class HelloをHTML内のid='main'内にレンダリングせよ、という命令。
ReactDOM.render(
    <Hello />,
    document.getElementById('main')
)

今風の書き方

  • var HelloWorld = React.createClass{~~}はもう使わない。代わりにclassを使う。
  • 自作メソッドを使うときはconstructor(props)内でメソッドとthis.をバインドしなければならない。
  • stateの初期化にもはやgetInitialState()は使わない。

var HelloWorld = React.createClass{~~}はもう使わない。代わりにclassを使う。

var HelloWorld = React.createClass{~~}と書き始めていたが、今はReact.Componentを継承して新しいクラスを作るのが良いらしい。ES6的書き方に慣れていればこっちのがわかりやすい。

今風の書き方
class HelloWorld extends React.Component {
    render(){
        // QiitaはJSXに対応していないので、おそらくh1がハイライトされている。が、問題なし。
        return (<h1>Hello World</h1>)
    }
}

ちなみに、以前のReact.createClass{~~}も今しばらくは使用できる。違いについてはこの記事が詳しかった。ES6以降の書き方をするのであれば、React.Componentを使用するのが良さそうだ。

ES5のReact.jsソースをES6ベースに書き換える - Qiita

最後に同じ挙動をするコードの比較を書いておく。

// これは古い書き方
var HelloWorld = React.createClass({
    render: function() {
        return (
            <div className="hw">
                Hello World.
            </div>
        );
    }
});

多くの場合は下のようにメソッド定義時の無名関数の書き方が変わるだけで済む。もともとES6を書いていた人は脳内変換が簡単ではないかと思う。

// 新しい書き方
class HelloWorld extends React.Component{
    render(){ // function()がなくなり、ES6と同じメソッド的書き方になっている。
        return (
            <div className="hw">
                Hello World.
            </div>
        );
    }
}

自作メソッドを使うときはconstructor(props)内でメソッドとthis.をバインドしなければならない。

これは、コードの中でthis.というワードを使用するときには必ず行わなければならない。

例えば、自身で新しいメソッドを定義する場合。 インターネット上で見つけた情報をES6的書き方にしているだけなのに動かない、ということがよくある。
下は、ボタンを追加し、押されたときに何らかの処理をしたい場合の例。動かない例では、ButtonOnClickなんてメソッドは無いと怒られる。

// 動かない。
class HelloWorld extends React.Component{
    ButtonOnClick(){
        /**
         * ボタンが押されたときの処理
        **/
    }
    render(){
        return (
            <div className="hw">
                Hello World.
                <Button onClick={this.ButtonOnClick}>CLICK!</Button>
            </div>
        );
    }
}

これは、classを継承した時点ではthisが初期化されていないため。詳しいことはこちらの記事にかかれている。
そのため、まずconstructor()内でsuper();を呼び出し、thisを初期化後、そのthisをメソッドにバインドするという一連の作業が必要である。(追記予定)

// 動く。
class HelloWorld extends React.Component{
    // ここに注目
    constructor(props) {
        super(props);
        this.ButtonOnClick = this.ButtonOnClick.bind(this);
    }

    ButtonOnClick(){
        /**
         * ボタンが押されたときの処理
        **/
    }
    render(){
        //             同上
    }
}

stateの初期化にもはやgetInitialState()は使わない。

これもハマったポイントの一つ。getInitialState()メゾットを書く必要はなく、constructor()内でそのまま代入すればよい。

class Contents extends React.Component {
    constructor(props) {
        super(props);
        this.state = { ID: 0, result: {}, value : '' };
    }
    render(){
        //             同上
    }
}

ただしthis.setState();は健在。値を変更する時にthis.stateに直接代入してはいけない。

あとがき

自身も初学者なので、何かここ違うよという指摘がありましたらコメントしていただけると幸いです。よろしくお願いします。