おーじぇいブログ

ただひたすらに書きます。

Reactを学ぶ。3日目 Reactとは何か~インタラクティブなコンポーネントまで

前回の記事はこちらです。

920oj.hatenablog.com

前回までで環境構築が終わり、いよいよReactを学んでいく準備ができました。今回からは、公式チュートリアルに沿ってReactを学習していきたいと思います。

ja.reactjs.org

Reactとは?

React はユーザーインターフェイスを構築するための、宣言型で効率的で柔軟な JavaScript ライブラリです。複雑な UI を、「コンポーネント」と呼ばれる小さく独立した部品から組み立てることができます。

うん、ちょっとタイム。いきなり沢山の横文字が出てきて少し混乱したので、ちょっとずつ紐解いていきます。

まずReactというのはJavaScriptのライブラリ。一見違う言語のように見えて、結局はJavaScriptで動作しているもの。数あるJavaScriptのライブラリの中でも、Reactは「UIを構築するため」に使われるものらしい。さらに、特徴として

  • 宣言型
  • 効率的
  • 柔軟

という3つの利点が挙げられています。これ以上を追っていくとキリが無いので、ふーん、いいとこあんじゃん みたいなノリで良しとしました。理解するのはコード書いてからじゃい。

コンポーネント

んで、アプリを充実させていこうとすると、どうしても複雑なUIになってしまいます。わかるよ、Facebookアプリとかどこ押したらQRコード出てくるかわからんもん。

そうなってしまった複雑なUIを、小さな「コンポーネント」という部品に分けてコードを書くことができる、ということです。

現段階のindex.jsを見る限り、3つのクラスが書かれています。それぞれ、

  • Square
  • Board
  • Game

です。そして、これら一つ一つは「Reactコンポーネント」のクラスです。React.Componentから継承することにより、これらのクラスはそれぞれ「Squareコンポーネント」「Boardコンポーネント」「Gameコンポーネント」となります。

f:id:OJ920:20190504224227p:plain

この色がそれぞれの色に対応している、と考えるとわかりやすいですね。Boardクラスの中にSquareクラスが9つあり、またGameクラスの中にBoardクラスと文字・ボタンが組み込まれています。

チュートリアルでは、ショッピングリストのコードが例として挙げられています。

class ShoppingList extends React.Component {
  render() {
    return (
      <div className="shopping-list">
        <h1>Shopping List for {this.props.name}</h1>
        <ul>
          <li>Instagram</li>
          <li>WhatsApp</li>
          <li>Oculus</li>
        </ul>
      </div>
    );
  }
}

// Example usage: <ShoppingList name="Mark" />

コンポーネントは、React に何を描画したいかを伝えます。データが変更されると、React はコンポーネントを効率よく更新して再レンダーします。

コンポーネントは props(“properties” の略)と呼ばれるパラメータを受け取り、render メソッドを通じて、表示するビューの階層構造を返します。

最終行にある、 <ShoppingList name="Mark" /> の、nameの値がデータということでしょうか。propsのパラメータであるnameの値が変更されると、コンポーネント側にこの値が受け渡されて、renderメソッド内の {this.props.name}が変更される――コンポーネントを更新・再レンダーする……らしいです。

JSX

render は、描画すべきものの軽量な記述形式である React 要素というものを返します。たいていの React 開発者は、これらの構造を簡単に記述できる “JSX” と呼ばれる構文を使用しています。

さっきからJavaScriptのコードの中にHTMLがあって気持ち悪いなぁという気分がしてました。どうにもReactではReact要素の構造を記述するために、JSXという構文を使っており、その中にはHTMLタグが直接埋め込まれるようになっている模様。

どのような JavaScript の式も JSX 内で中括弧に囲んで記入することができます。各 React 要素は、変数に格納したりプログラム内で受け渡ししたりできる、JavaScript のオブジェクトです。

JSXの中でJavaScriptの式を書く場合は、{}で囲まなければならないらしいです。例えば

<h1>{10+1}</h1>

のように記述すれば、h1タグで囲まれた11が出てきます。

コンポーネントを使う

上記の ShoppingList コンポーネント<div /><li /> といった組み込みの DOM コンポーネントのみをレンダーしていますが、自分で書いたカスタム React コンポーネントを組み合わせることも可能です。例えば、<ShoppingList /> と書いてショッピングリスト全体を指し示すことができます。

これが最大の利点なんじゃないでしょうか。上記のコードでShoppingListというコンポーネントを作っていましたが、これは、JSXの中で`と書けば使える(指し示す)ことができるようです。

なるほど、これで書くことができるのだったら、コンポーネントを再利用して柔軟にコーディングすることができますね。Reactが選ばれるのも納得です。

データを Props 経由で渡す

先程のセクションで中身を確認するのはやってしまったので、さっそくコードに手を加えていくようです。なんだかワクワクしますね。

現状はポツンと3つのコンポーネントが独立しているだけで、Reactの恩恵は受けられていません。これを書き換えて、”””インタラクティブ”””なものにしていきましょう、というのがこのセクション。

BoardクラスのrenderSquareメソッドを書き換えていきます。まずは変更前、index.jsの15行目から。

class Board extends React.Component {
  renderSquare(i) {
    return <Square />;
  }

これを、

class Board extends React.Component {
  renderSquare(i) {
    return <Square value={i}/>;
  }

に書き換えます。すると、Squareコンポーネントに、valueの値がpropsとして受け渡されます。

さらに、この受け渡されたvalueの値を活かすために、Squareコンポーネントを書き換えます。index.jsの5行目より、

class Square extends React.Component {
  render() {
    return (
      <button className="square">
        {/* TODO */}
      </button>
    );
  }
}

これを、

class Square extends React.Component {
  render() {
    return (
      <button className="square">
        {this.props.value}
      </button>
    );
  }
}

this.props.valueにします。こんな感じに値が受け渡されていくんですね~

f:id:OJ920:20190504231914p:plain

と、いうことで実際に数字を表示させることができました。うん、一歩前進。 f:id:OJ920:20190504232444p:plain

インタラクティブコンポーネントを作る

クリックされたら動作

クリックされたら何をするか……そう、アイツです。ボタンをクリックしたら、は onClickですよね!実際にはイベントリスナーを用いるべきなんでしょうが、自分が受けていた講義ではずっとonClickでした。

index.jsの8行目を以下に書き換えます。

<button className="square" onClick={() => alert('click')}>

それはさておき、ここでのonClickはpropsなので、関数を渡さないと、クリックしていないにもかかわらず実行され続けてしまいます。また、ここではアロー関数の記法が用いられているようです。出たよES6……

(引数,...)=>{...関数本体...}

でしたね!

state

で、ここまではPropsの説明でした。Propsは「親から渡されるプロパティ」のことでしたね。続いて、「そのコンポーネントが持っている”状態”」のことを指すstateに移ります。

React コンポーネントはコンストラクタで this.state を設定することで、状態を持つことができるようになります。this.state はそれが定義されているコンポーネント内でプライベートと見なすべきものです。

うーん、ややこしい。とりあえずコードを書き換えて理解していきます。

クラスが呼び出されたときに実行される「コンストラクタ」を用いて、stateを初期化、this.props.valuethis.state.value に置き換え、onClick={() => this.setState({value: 'X'})}を追加、以上の書き換えを行うと、

index.js 5行目、Squareクラス

class Square extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            value: null,
        };
    }

    render() {
        return (
            <button
                className="square"
                onClick={() => this.setState({ value: 'X' })}
            >
                {this.state.value}
            </button>
        );
    }
}

こうなります。コンストラクタで初期化、というのはまあわかります。その後、onClickプロパティで「setStateメソッドでvalueオプションをXにする」という関数を実行し、またそのボタンの内容をXにする、といったものです。

squareというclassName(props)のボタンをクリックすると、Squareクラスのvalueというstateの値をXにする、ということでしょうか。

う~んややこしい。でも、確かにやっていることはどうにか理解できますね。

現時点でのコード

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

class Square extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            value: null,
        };
    }

    render() {
        return (
            <button
                className="square"
                onClick={() => this.setState({ value: 'X' })}
            >
                {this.state.value}
            </button>
        );
    }
}

class Board extends React.Component {
    renderSquare(i) {
        return <Square value={i} />;
    }

    render() {
        const status = 'Next player: X';

        return (
            <div>
                <div className="status">{status}</div>
                <div className="board-row">
                    {this.renderSquare(0)}
                    {this.renderSquare(1)}
                    {this.renderSquare(2)}
                </div>
                <div className="board-row">
                    {this.renderSquare(3)}
                    {this.renderSquare(4)}
                    {this.renderSquare(5)}
                </div>
                <div className="board-row">
                    {this.renderSquare(6)}
                    {this.renderSquare(7)}
                    {this.renderSquare(8)}
                </div>
            </div>
        );
    }
}

class Game extends React.Component {
    render() {
        return (
            <div className="game">
                <div className="game-board">
                    <Board />
                </div>
                <div className="game-info">
                    <div>{/* status */}</div>
                    <ol>{/* TODO */}</ol>
                </div>
            </div>
        );
    }
}

// ========================================

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

ここまでの疑問点

  • JSXのタグ、classNameは通常のHTMLのタグのclassと何が違うのか?

  • コンストラクタ内でsuper()を書くのは何故? →これを後で読む

qiita.com

まとめ

  • Reactとは、JavaScriptフレームワークで「UIを構築するため」に使われる。
  • 複雑なUIを実現するために、小さな「コンポーネント」という部品に分けてコードを書くことができる。
  • コンポーネントは、「props」と呼ばれるパラメータを受け取って、インタラクティブな動作を実現する
  • JSXの中でコンポーネントを独自のタグとして記述することができる
  • onClick={() => 関数の内容} というpropsで、「クリックしたら」という動作を書く
  • コンポーネントの状態を表すには「state」を使う。stateを初期化するにはコンストラクタで初期化する記述をする

始めの入り、ということでちょっと長く書きすぎた気がします。こんどからはもうちょっとサクっと書けるように……でないとモチベが持たない。 とりあえず3日目の記事は以上でおしまいです。

もし間違えやわかりやすい説明があったらコメントで教えてくださると助かります。それでは!