HTML5テクニカルノート
Create React App 入門 01: 3×3のマス目をつくる
- ID: FN1912002
- Technique: ECMAScript 2015
- Library: React 16.12.0
ReactはFacebook社が開発している、今もっとも注目されているJavaScriptフレームワークです(「JavaScript: フレームワーク React/Vue/Angularについて」参照)。DOM(Document Object Model)の要素をデータと関連づけて(データバインディング)、データの変化に応じてページを動的に構成します。ただ、なじみの少ない構文の知識や準備が求められるため、なじみのない方には少し始めにくいかもしれません。公式Reactサイトには「チュートリアル:React の導入」がありますので、これを読むのがひとつの手です。CodePenにでき上がりのコードも掲げられています(サンプル001)。
もっとも、コードはコンポーネント分けされてはいるものの、ひとつのJavaScriptファイルです。「Create React App」を使えば、モジュール分けされたシングルページアプリケーション(SPA)のひな形が簡単につくれます。そのひな形に手を加えてチュートリアルと同じマルバツゲームに仕上げようというのが、この「Create React App 入門」シリーズです。
サンプル001■Tic Tac Toe
See the Pen Tic Tac Toe by Dan Abramov (@gaearon) on CodePen.
01 Reactアプリケーションのひな形をつくる
まずは、Create React Appのインストールです。予めNode.js(npm)が入っていなければなりません。コマンドラインツールからnpmでつぎのコマンドを打ち込んでください。
npm install -g create-react-app
npx create-react-app
コマンドにつづけてアプリケーション名(react-tic-tac-toe
としました)を入力すると、その名前でフォルダとアプリケーションのひな形がつくられます。
npx create-react-app react-tic-tac-toe
ひな形がつくられたら、アプリケーションのディレクトリに移って、npm startとコマンドを打てば、ローカルサーバーでひな形のページが開きます(図002)。ローカルサーバーを閉じたいときは[control]/[Ctrl] + [C]、再開には改めてnpm start
を入力してください。
cd react-tic-tac-toe npm start
図001■ひな形のReactアプリケーションのページ
02 マス目のコンポーネントをつくってアプリケーションに差し込む
src/App.js
は大もとになるコンポーネントです。ひな形アプリケーションには、ほかのコンポーネントはまだありません。コンポーネントは新たにsrc/components
というフォルダにまとめましょう。src/App.js
はsrc/App.css
とともに、このフォルダに移してください。
src/App.css
→src/components/App.css
src/App.js
→src/components/App.js
また、つぎの4つのファイルは使わないので、削除してかまいません。
src/App.test.js
×src/logo.svg
×src/serviceWorker.js
×src/setupTests.js
×
アプリケーションのスタイルシートsrc/components/App.css
は、前掲サンプル001のCodePenのCSSコードをそのまま使います。つぎのコードからコピーしてもよいでしょう。
src/components/App.cssbody { font: 14px "Century Gothic", Futura, sans-serif; margin: 20px; } ol, ul { padding-left: 30px; } .board-row:after { clear: both; content: ""; display: table; } .status { margin-bottom: 10px; } .square { background: #fff; border: 1px solid #999; float: left; font-size: 24px; font-weight: bold; line-height: 34px; height: 34px; margin-right: -1px; margin-top: -1px; padding: 0; text-align: center; width: 34px; } .square:focus { outline: none; } .kbd-navigation .square:focus { background: #ddd; } .game { display: flex; flex-direction: row; } .game-info { margin-left: 20px; }
src/index.css
のCSSはアプリケーションにあまり影響しません。body
の定めだけ残しました。
src/index.cssbody { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } /* code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } */
つぎの抜き書きが、モジュールsrc/index.js
で変更するコードです。HTMLのタグ<>
がスクリプトの中に直に書き込まれています。この特有の構文が「JSX」です。ReactDOM.render()
メソッドはReactの要素をHTMLドキュメントに差し込みます。第1引数がつくるコンポーネント(App
)、第2引数は差し込む先の親要素です。コンポーネントはフォルダを移しましたので、import
のパスは書き替えました。また、前述のとおりserviceWorker
は使いません。
src/index.js//import App from './App'; import App from './components/App'; // import * as serviceWorker from './serviceWorker'; ReactDOM.render(<App />, document.getElementById('root')); // 変更なし // serviceWorker.unregister();
ルートの関数コンポーネントsrc/components/App.js
は、つぎのように大幅に書き替えます。import
に加えたSquare
は、このあと定める新たな子コンポーネントです。コンポーネントの関数(App()
)は、JSXで書いた要素の定めを返します。この戻り値がコンポーネントとして描画される要素です。つまり、子コンポーネントが入れ子でページに差し込まれます。なお、class
属性はclassName
に替えなければなりません。class
がECMAScript 2015の予約語になっているためでしょう。また、テンプレートは必ずひとつのルート要素にまとめてください。
src/components/App.jsimport React from 'react'; import Square from './Square'; // import logo from '../logo.svg'; import './App.css'; function App() { return ( /* <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> */ <div className="game"> <Square /> </div> ); } export default App;
新しい子の関数コンポーネントsrc/components/Square.js
の定めはつぎのとおりで、<button>
要素をひとつもつだけです。ここではアロー関数式=>
を用いました。function
による定義と基本的に違いはありません。関数は引数(props
)をひとつ受け取ります。今はまだ使いません。動きを確かめると、src/components/App.css
のスタイルにより、ページにはマス目がひとつ描かれます(図002)。
src/components/Square.jsimport React from 'react'; const Square = (props) => { return ( <button className="square"> </button> ); }; export default Square;
図002■ページに描かれたマス目
src/index.js
にはもう手を加えませんので、コード001に掲げます。
コード001■ページにReactのルートモジュールを加える
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';
ReactDOM.render(<App />, document.getElementById('root'));
03 9マスの盤面を組み立てる
マルバツゲームの盤面は3×3の9マスです。つぎのコード002の新たなコンポーネントsrc/components/Board.js
で、マス目の子コンポーネント(Square
)を使って組み立てました。JSXの構文の中に波かっこ{}
を使うと、JavaScriptの式が書けます。つまり、変数(プロパティ)を参照したり、関数(メソッド)が呼び出せるのです。関数コンポーネントが返すテンプレートでは、3コマから1行をつくる<div>
要素の中から関数(renderSquare()
)を呼び出しています。そして、マス目(Square
)の子コンポーネントをそれぞれ受け取って加えているのです。関数の引数(i
)が子コンポーネントに、波かっこ{}
で属性(value
)の値として与えられていることにご注目ください。
コード002■3×3マスのゲーム盤面をつくる
src/components/Board.js
import React from 'react';
import Square from './Square';
const Board = (props) => {
const renderSquare = (i) =>
<Square value={i} />;
return (
<div>
<div className="board-row">
{renderSquare(0)}
{renderSquare(1)}
{renderSquare(2)}
</div>
<div className="board-row">
{renderSquare(3)}
{renderSquare(4)}
{renderSquare(5)}
</div>
<div className="board-row">
{renderSquare(6)}
{renderSquare(7)}
{renderSquare(8)}
</div>
</div>
);
};
export default Board;
テンプレートでコンポーネントの属性に渡された値を受け取るのが、関数コンポーネントの引数(props
)です(「コンポーネントとprops」参照)。属性をプロパティとして参照すれば、値が取り出せます。子コンポーネントsrc/components/Square.js
は、つぎのようにマス目の中に属性(value
)の値をテキストとして示すようにしてみました。
src/components/Square.jsconst Square = (props) => { return ( <button className="square"> {props.value} </button> ); };
ルートコンポーネント
src/components/App.js
は、差し込む子コンポーネントをマス目(Square
)から盤面(Board
)に替えます。これで、3×3の9つのマス目が描かれ、それぞれに連番整数が示されるはずです(図003)。
src/components/App.js// import Square from './Square'; import Board from './Board'; function App() { return ( <div className="game"> {/* <Square /> */} <Board /> </div> ); }
図003■9つのマス目に連番整数が示された
書き上がったマス目(src/components/Square.js
)とルート(src/components/App.js
)のコンポーネントは、つぎのコード003のとおりです。併せて、動きとそれぞれのモジュールの中身が確かめられるように、以下のサンプル002をCodeSandboxに掲げました。
コード003■3×3のマス目でゲーム盤面をつくる
src/components/Square.js
import React from 'react';
const Square = (props) => {
return (
<button className="square">
{props.value}
</button>
);
};
export default Square;
import React from 'react';
import Board from './Board';
import './App.css';
function App() {
return (
<div className="game">
<Board />
</div>
);
}
export default App;
サンプル002■Create React App: Tic Tac Toe 01
Create React App 入門
- Create React App 入門 01: 3×3のマス目をつくる
- Create React App 入門 02: クリックしたマス目にXをつける
- Create React App 入門 03: マルバツで勝ち負けを決める
- Create React App 入門 04: ゲームの履歴をさかのぼる
- Create React App 入門 05: 無駄な処理を省く
作成者: 野中文雄
作成日: 2019年12月30日
Copyright © 2001-2019 Fumio Nonaka. All rights reserved.