【React】公式のチュートリアルをやってみる~①環境構築 の続きです。
プロジェクトファイルを作成して、プログラムを読んでみました。
ソースファイル配置
- src フォルダ内のファイルを削除する
- index.css, index.js を作成する
index.css
body {
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;
}
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
class Square extends React.Component {
render() {
return (
<button className="square">
{/* TODO */}
</button>
);
}
}
class Board extends React.Component {
renderSquare(i) {
return <Square />;
}
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>
);
}
}
// ========================================
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Game />);
・・・よく分からない!!!ので、現在のプログラムを解析してみる
プログラム解析
ページ表示用のテンプレート
public/index.html
<!DOCTYPE html>
<html lang="en">
<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" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enabe JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
- 先ほど表示されたページのテンプレートファイル
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
- linkタグのhrefの
"%PUBLIC_URL%/
はビルド時にpublicフォルダへのパスに置き換わる
<div id="root"></div>
- divタグの
id="root"
に対して、Reactのコードが埋め込まれる- React DOM によって管理されることになる
JavaScript のエントリーポイント
src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
class Square extends React.Component {
render() {
return (
<button className="square">
{/* TODO */}
</button>
);
}
}
class Board extends React.Component {
renderSquare(i) {
return <Square />;
}
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>
);
}
}
// ========================================
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Game />);
- JavaScriptのエントリーポイントとなっているファイル
- 3つのコンポーネントが定義されている
- Square(正方形のマス目)
- Board(盤面)
- Game
- Square(マス目)コンポーネントは 1 つの
<button>
をレンダーし、Board(盤面)が 9 個のマス目をレンダーしていて、Game コンポーネントは盤面とプレースホルダーを描画している- Game → Board → Square
import React from 'react';
import ReactDOM from 'react-dom/client';
- npmでインストールしたモジュールをインポートする
- React
- React ライブラリのエントリーポイント
- ReactDOM
- アプリのトップレベルで使うための DOM 特有のメソッドを提供している
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Game />);
- React要素をルートDOMノードにレンダーするには、ReactDOM.createRoot() にDOM要素を渡し、root.render() にReact 要素を渡す
- ここでは、
Game
というReactコンポーネントが渡されている- ユーザ定義のコンポーネントの名前は大文字で始める
- ここでは、
Gameコンポーネント
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>
);
}
}
- Reactコンポーネントクラス
Game
を定義している- Reactでは、UI を「コンポーネント」と呼ばれる小さく独立した部品から組み立てることができる
-
render()
は、コンポーネントクラスで必ず定義しなければならない唯一のメソッド- JSX構文で作成されたReact要素を返す
- JSXとは、JavaScriptにマークアップを書くことができる構文で、BabelでJavaScriptに変換される
- JSX構文で作成されたReact要素を返す
- CSS のクラスをコンポーネントに適用するには、
className
プロパティにクラス名を指定する - JSX内で、
Board
というReactコンポーネントが呼ばれている- コンポーネントは自身の出力の中で他のコンポーネントを参照できる
Boardコンポーネント
class Board extends React.Component {
renderSquare(i) {
return <Square />;
}
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>
);
}
}
- マスの1行ごとに3回
renderSquare()
を実行している- JSXでは、
{}
で囲むことで式を埋め込むことができる
- JSXでは、
- ステータスとして、
Next player: X
を表示している- この文字列は、定義した
status
変数を使用している
- この文字列は、定義した
-
renderSquare
関数では、Square
というReactコンポーネントが返される
Squareコンポーネント
class Square extends React.Component {
render() {
return (
<button className="square">
{/* TODO */}
</button>
);
}
}
- 1つのボタンを返している