🎃

【React】チュートリアルやってみた②

2021/05/07に公開

環境

Windows10Pro

目次

①Reactのプロジェクトを作成し、Webからアクセスできることを確認する。
https://zenn.dev/taka_tech/articles/773da5de8c822a
②クリックしたマスに×を表示させる。←ここ
③手番を追加し、クリック時に〇と×が交互に表示されるようにする。
https://zenn.dev/taka_tech/articles/e1c0b0b01e9b96
④勝利判定を実装する。
https://zenn.dev/taka_tech/articles/d52991cdb0cbfd
⑤履歴機能を実装する。
https://zenn.dev/taka_tech/articles/141760436bef12

最終目標

Reactチュートリアルの三目並べゲームを作成する
https://ja.reactjs.org/tutorial/tutorial.html

目標②

クリックしたマスに×を表示させる。

実践

データをProps経由で渡す

BoardコンポーネントのrenderSquareメソッドでvalueという名前でデータをSquareコンポーネントに渡すようにする。

index.js
// Squareコンポーネント
class Square extends React.Component {
    render() {
      return (
        <button className="square">
+          {this.props.value}
        </button>
      );
    }
  }
  
// Bordコンポーネント
class Board extends React.Component {
    renderSquare(i) {
+      return <Square value={i}/>;
    }

クリックイベントを設定する

アラートを発するクリックイベント

アロー関数構文を使ってonClickイベントでアラートが出るようにする。

index.js
class Square extends React.Component {
    render() {
      return (
+        <button className="square" onClick={() => alert('click')}>
          {this.props.value}
        </button>
      );
    }
}

クリックしたマスに×を表示

クリックしたマスに×を表示するクリックイベントを作成する。
stateを使って状態を保存する。コンストラクタでstateを設定し、クリックイベントでstateを変更するようにする。

index.js
  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>
      );
    }
}

React Developer Tools

propsやstateの情報を見ることができるChromeの拡張機能。
https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
拡張機能の設定でファイルの URL へのアクセスを許可する。

ブラウザで確認する。

ブラウザを更新しマスをクリックすると、クリックしたマスに×が表示されることを確認できる。またF12を押下してディベロッパーツールを開き、拡張機能部分を選択すると、props、stateを確認することができる。

stateのリフトアップ

ゲームの状況を親コンポーネントのstateにリフトアップさせることで子コンポーネントで同期がとれるようにする。子コンポーネントにデータを渡すときは、propsを用いるようにする。
Boardコンポーネントのコンストラクタで9つのマスの状態をstateで保存するようにする。

index.js
class Board extends React.Component {
    // コンストラクタ
 +   constructor(props) {
 +       super(props);
 +       this.state = {
 +           squares: Array(9).fill(null),
 +       };
 +   }

    renderSquare(i) {
        return <Square value={i}/>;
    }

SquareコンポーネントでBoardコンポーネント(親)のstateを扱うために、renderSquareメソッドで、valueとonClickを設定します。

index.js
    renderSquare(i) {
        return (
            <Square
+                value={this.state.squares[i]}
+                onClick={
+                    () => this.handleClick(i)
+                }
            />
        )
    }

クリックしたときに、stateのクリックしたマスに×の状態を保存するhandleClickメソッドを作成します。

index.js
    handleClick(i) {
        const squares = this.state.squares.slice();
        squares[i] = 'X';
        this.setState({squares: squares});
    }

リフトアップするので、Squareコンポーネントのコンストラクタを削除します。
また、ボタンのクリックイベントにBoardコンポーネントから渡ってきたpropsのクリックイベントを設定します。

index.js
class Square extends React.Component {
-   constructor(props) {
-        super(props);
-        this.state = {
-          value: null,
-        };
-      }
    render() {
        return (
            <button
                className="square"
                onClick={
+                    () => this.props.onClick()
                }
            >
                {this.props.value}
            </button>
        );
    }
}

stateを持たないコンポーネントを関数コンポーネントにする

React.Component を継承するクラスを定義する代わりに、props を入力として受け取り表示すべき内容を返す関数を定義します。

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

Discussion