0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Reactとfirebaseでアプリケーションを作る①

Last updated at Posted at 2020-05-14

ReactとFirebaseでアプリケーションを作る①

①では、環境作成と下地作りまでです。

やりたいこと

  • Reactのチュートリアルで基礎を学ぶ
  • チュートリアルを参考に、一人神経衰弱ゲームを作る
  • Firebase Authentication を使ってログイン認証する
  • Firebase を使ってデータを管理する

チュートリアルを修正して、一人神経衰弱ゲームを作る

チュートリアルは、「チュートリアル:React の導入」を利用する。
今回、理解するポイントはチュートリアルの通り。

チュートリアルの準備:以下のチュートリアルを進めるにあたっての開始地点です。
概要:コンポーネントや props、state といった基礎概念について学びます。
ゲームを完成させる:React での開発における非常によくある技法について学びます。

チュートリアルの準備

環境を作る

以前作成したDockerのReact環境「DockerにReact環境を構築する」をクローンする。

git clone https://github.com/abiitaka/docker-react.git react-firebase

docker-compose.ymlinit.sh のプロジェクト名を変更する。

  • 変更前:reactstudy01 → 変更後:react-firebase

以降は、チュートリアルの不要なファイルを削除するところから進めていく。

Reactのチュートリアルで基礎を学ぶ

三目並べを作る

チュートリアルに従って進めていくと三目並べは完成する。

作ったソースは以下にあります。
三目並べ作成

チュートリアルのポイント

Reactのチュートリアルでは、リフトアップとイミュータビリティについて補足説明をしている。
以下の2点がポイントです。

リフトアップ

複数の子要素からデータを集めたい、または 2 つの子コンポーネントに互いにやりとりさせたいと思った場合は、代わりに親コンポーネント内で共有の state を宣言する必要があります。親コンポーネントは props を使うことで子に情報を返すことができます。こうすることで、子コンポーネントが兄弟同士、あるいは親との間で常に同期されるようになります。

このように state を親コンポーネントにリフトアップ (lift up) することは React コンポーネントのリファクタリングでよくあることですので、この機会に挑戦してみましょう。

また、「state のリフトアップ」にも、まとめられています。

イミュータビリティ

**ミュータブル (mutable) なオブジェクトは中身が直接書き換えられるため、変更があったかどうかの検出が困難です。**ミュータブルなオブジェクト変更の検出のためには、以前のコピーと比較してオブジェクトツリーの全体を走査する必要があります。

**イミュータブルなオブジェクトでの変更の検出はとても簡単です。**参照しているイミュータブルなオブジェクトが前と別のものであれば、変更があったということです。

mutable、immutableの変更検出は、scpとして「shouldComponentUpdate の実際の動作」にまとめられています。

チュートリアルを参考にひとり神経衰弱ゲームを作る

ルール

  • 4x3のマス目を作る
  • マスに1〜6までの数字のペアを配置する
  • 1つ目をクリックすると数字が表示される
  • 2つ目をクリックすると数字が表示される
  • 表示した2つの数字がペアかどうか判断する
  • ペアであれば表示したまま、ペアでなければ表示しない

ソース


class Board extends React.Component {
    constructor(props) {
        super(props);

        const squareCount = 12;
        const initGameBoard = this.generateBoard(squareCount);

        this.state = {
            gameBoard: initGameBoard,
            selectBoard: Array(squareCount).fill(null),
            history: [{ selectBoard: Array(squareCount).fill(null) }],
            previous: null,
            isPair: null,
        }
    }

    handleClick(current) {
        // 盤表示
        const selectBoard = this.state.selectBoard.slice();
        selectBoard[current] = this.state.gameBoard[current];

        // ペア判定
        let isPair = null, previous = null;
        if (this.state.previous == null) {
            previous = current;
        } else {
            isPair = this.isPair(selectBoard[this.state.previous], selectBoard[current]);
        }

        // 履歴
        const history = this.state.history.slice();

        this.setState({
            selectBoard: selectBoard,
            history: history.concat([{ selectBoard: selectBoard }]),
            previous: previous,
            isPair: isPair,
        });
    }

    // 盤のペア組み合わせ生成
    generateBoard(squareCount) {
        let result = [];
        // ペアの数字を生成
        for (let i = 1; i <= squareCount / 2; i++) {
            result.push(i, i);
        }
        // シャッフル(Fisher-Yates shufflアルゴリズム)
        for (let i = squareCount - 1; i > 0; i--) {
            let random = Math.floor(Math.random() * (i + 1));
            let tmp = result[i];
            result[i] = result[random];
            result[random] = tmp;
        }
        return result;
    }

    // ペアをチェックする
    isPair(previous, current) {
        if (previous == null && current == null) {
            return false;
        } else if (previous === current) {
            return true;
        } else {
            return false;
        }
    }

    renderSquare(i) {
        return (
            <Square
                value={this.state.selectBoard[i]}
                onClick={() => this.handleClick(i)}
            />
        );
    }

    render() {
        // ペアにならない場合は盤を戻す 
        if (this.state.isPair === false) {
            setTimeout(() => {
                const history = this.state.history.slice(0, this.state.history.length - 2);
                const selectBoard = history[history.length - 1].selectBoard.slice();
                this.setState({
                    selectBoard: selectBoard,
                    history: history,
                    isPair: null,
                });
            }, 300);
        }
        return (
            <div>
                <p>{this.state.selectBoard.indexOf(null) === -1 ? 'ゲーム終了' : ''}</p>
                <div className="board-row">
                    {this.renderSquare(0)}
                    {this.renderSquare(1)}
                    {this.renderSquare(2)}
                    {this.renderSquare(3)}
                </div>
                <div className="board-row">
                    {this.renderSquare(4)}
                    {this.renderSquare(5)}
                    {this.renderSquare(6)}
                    {this.renderSquare(7)}
                </div>
                <div className="board-row">
                    {this.renderSquare(8)}
                    {this.renderSquare(9)}
                    {this.renderSquare(10)}
                    {this.renderSquare(11)}
                </div>
            </div>
        );
    }
}

作ったソースは以下にあります。
一人神経衰弱ゲーム作成

Firebase Authentication と Firebase は、「ReactとFirebaseでアプリケーションを作る②(準備中)」でまとめます。

Firebase作成

Firebase プロジェクトを作成する

image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?