グローバルナビゲーションへ

本文へ

フッターへ

お役立ち情報Blog



【React.js入門】関数コンポーネントで百マス計算を生成してみる

 

現在進行中のプロジェクトの為、goに入門して半年以上が経ちました。
goには多少なれてきたのですがこのプロジェクトでのフロントエンドにはReact.jsを採用することが決まっています。
vue.jsなどは多少触ったことがありますが、React.jsは初めての挑戦です。

React.js&Next.js超入門第二版を一通り読んでみて超入門は果たした状態ですがまだ全く身になっていません。
とりあえず何か作ってみないと身にならないので今回は本の4章あたりまでの知識を利用して百マス計算を生成するサンプルを作成してみようと思います。

完成したサンプルはこちらです

開発環境

$ node --version
v15.2.0
$ npm --version
7.0.8<

Step1.プロジェクトの作成

$ npx  --legacy-peer-deps create-react-app hyakumasu

※プロジェクト作成時に↓ のようなエラーが出たので「–legacy-peer-deps」を追加しています。

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
・・・

開発用サーバを起動して初期画面が表示されることを確認します。

$ cd hyakumasu
$ npm start

ブラウザが勝手に起動し「http://localhost:3000」で初期画面が表示されます。

Step2.開発前の下準備

今回のアプリの見た目は「React.js&Next.js超入門」にならって、Bootstrapを利用します。 その為にまずはhyakumasu/public/index.htmlを書き換えます。

  • public/index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>百マス計算</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" crossorigin="anonymous">
  </head>

  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>

</html>

次にhyakumasu/src/App.cssを調整します。既存のApp.cssの下に以下を追記します。

h1 {
  text-align: left;
  padding: 0px, 50px, 10px, 50px;
  margin: 0px, 0px, 10px, 0px;
}

.subtitle {
  margin: 20px, 0px;
  color:#999;
  font-weight: bolder;
  font-size: 24pt;
}

あわせて、hyakumasu/src/App.jsを編集して初期画面を表示してみます。

import React from 'react';
import './App.css';

function App() {

  return (
    <div>
      <h1 className="bg-primary text-white display-4">百マス計算</h1>
      <div className="container">
        <table className="table table-bordered">
            <thead>
                <tr>
                    <th scope="col">#</th>
                    <th scope="col">1</th>
                    <th scope="col">2</th>
                    <th scope="col">3</th>
                    <th scope="col">4</th>
                    <th scope="col">5</th>
                    <th scope="col">6</th>
                    <th scope="col">7</th>
                    <th scope="col">8</th>
                    <th scope="col">9</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <th scope="row">1</th>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>

                ......

                <tr>
                    <th scope="row">9</th>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
            </tbody>
        </table>

        <div className="card p-3 border-primary text-center">
          <div><button className="btn btn-primary">再生成</button></div>
        </div>
      </div>
    </div>
  )
}

export default App;

ここまでで初期の見た目が設定できました。

Step3.useStateを利用して変数から表を作成する

まず最初のステップとしてuseStateの変数を作成し、表の繰り返しの部分をmapで実装してみます。

import React, { useState } from 'react';
import './App.css';

function App() {
  const [rows, setRows] = useState([1,2,3,4,5,6,7,8,9])
  const [cols, setCols] = useState([1,2,3,4,5,6,7,8,9])
  return (
    <div>
      <h1 className="bg-primary text-white display-4">百マス計算</h1>
      <div className="container">
        <table className="table table-bordered">
            <thead>
                <tr>
                    <th scope="col">#</th>
                    {rows.map((value) => (
                    <th scope="col">{value}</th>
                    ))}
                </tr>
            </thead>
            <tbody>
                    {cols.map((value) => (
                <tr>
                    <th scope="row">{value}</th>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                    ))}
            </tbody>
        </table>

        <div className="card p-3 border-primary text-center">
          <div><button className="btn btn-primary">再生成</button></div>
        </div>
      </div>
    </div>
  )
}

export default App;

行方向をrows変数、列方法をcols変数で定義して、その数字の配列をmapで繰り返しながらテーブルをレンダリングしています。見た目は変わっていません。

Step4.「再生成」ボタンをクリックしたら数値が変わるようにする

import React, { useState } from 'react';
import './App.css';

function App() {
  const [rows, setRows] = useState([0,1,2,3,4,5,6,7,8,9])
  const [cols, setCols] = useState([0,1,2,3,4,5,6,7,8,9])

  const reGenerate = () => {
    setRows(randomArray())
    setCols(randomArray())
  }

  const randomArray = () => {
    let arr = [0,1, 2, 3, 4, 5, 6, 7, 8, 9];
    let num = arr.length;

    //シャッフルアルゴリズム
    while (num) {
      let j = Math.floor(Math.random() * num);
      let t = arr[--num];
      arr[num] = arr[j];
      arr[j] = t;
    }

    return arr
  }

  return (
    <div>
      <h1 className="bg-primary text-white display-4">百マス計算</h1>
      <div className="container">
        <table className="table table-bordered">
            <thead>
                <tr>
                    <th scope="col">+</th>
                    {rows.map((value) => (
                    <th scope="col">{value}</th>
                    ))}
                </tr>
            </thead>
            <tbody>
                    {cols.map((value) => (
                <tr>
                    <th scope="row">{value}</th>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                    ))}
            </tbody>
        </table>

        <div className="card p-3 border-primary text-center">
          <div><button className="btn btn-primary" onClick={reGenerate}>再生成</button></div>
        </div>
      </div>
    </div>
  )
}

export default App;

関数を2つ新しく定義しています。 「reGenerate」関数は再生ボタンをクリックした際に呼び出され、rowsとcolsのステート値を変更しています。 ステート値が変更されると画面もフックの作用により自動的に変更されます。 「rondomArray」は0から10までの配列をシャッフルする関数です。 「再生成」ボタンに「onClick={reGenerate}」を設定したのでこれでボタンをクリックする度に表示が変更されていきます。

ここまでで百マス計算の生成機能の実装は完了しましたが、せっかくなので関数コンポーネントを分割してみます。

Step5.テーブルのヘッダー部分とそれ以外の部分を関数コンポーネントに分割してみる

import React, { useState } from 'react';
import './App.css';

function Rows(props) {
  return (
    <thead>
      <tr>
        <th scope="col">+</th>
        {props.rows.map((value) => (
          <th scope="col">{value}</th>
        ))}
      </tr>
    </thead>
  )
}

function Cols(props) {
  return (
    <tbody>
      {props.cols.map((value) => (
        <tr>
          <th scope="row">{value}</th>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
          <td></td>
        </tr>
      ))}
    </tbody>
  )
}

function App() {
  const [rows, setRows] = useState([0,1,2,3,4,5,6,7,8,9])
  const [cols, setCols] = useState([0,1,2,3,4,5,6,7,8,9])

  const reGenerate = () => {
    setRows(randomArray())
    setCols(randomArray())
  }

  const randomArray = () => {
    let arr = [0,1, 2, 3, 4, 5, 6, 7, 8, 9];
    let num = arr.length;

    //シャッフルアルゴリズム
    while (num) {
      let j = Math.floor(Math.random() * num);
      let t = arr[--num];
      arr[num] = arr[j];
      arr[j] = t;
    }

    return arr
  }

  return (
    <div>
      <h1 className="bg-primary text-white display-4">百マス計算</h1>
      <div className="container">

        <table className="table table-bordered">
          <Rows rows={rows} />
          <Cols cols={cols} />
        </table>

        <div className="card p-3 border-primary text-center">
          <div><button className="btn btn-primary" onClick={reGenerate}>再生成</button></div>
        </div>
      </div>
    </div>
  )
}

export default App;

3つの関数コンポーネント「App」、「Cols」、「Rows」に分割し、「App」のなかで 「Cols」、「Rows」を呼び出しています。 呼び出す際に値の受け渡しを行い、「Cols」、「Rows」側のpropsで受け取って利用しています。

さいごに

いかがだったでしょうか。Reactのほんの1部の機能しか利用していませんが、見通しよくすっきり記述することができました。 今回は単純に0~10までの数字をランダムに生成するだけでしたが、入力フォームを設けて生成する範囲を指定したり、作成した百マス計算の回答を生成したりする機能も比較的簡単に実装できるとおもいます。 ここからさらに改造して徐々にReactに慣れて行ければと思います。

この記事を書いた人

アーティス
アーティス
創造性を最大限に発揮するとともに、インターネットに代表されるITを活用し、みんなの生活が便利で、豊かで、楽しいものになるようなサービスやコンテンツを考え、創り出し提供しています。
この記事のカテゴリ

FOLLOW US

最新の情報をお届けします