8.3 まずは試してみる
6.3 フロントエンドの開発環境(Node.js+React)で開発環境をインストールし、"npm start " を実行すると、以下の画面がブラウザに表示されます。

この画面がどのように表示されているのかを見ていきます。インストールしたcreate-react-appによって生成されるサンプルアプリは、トップページであるindex.htmlが真っ先に呼び出され、その後index.js→App.jsというふうに実行されていきます。index.htmlはpublicフォルダの下に、index.jsとApp.jsはsrcフォルダの下にあります。
まず、index.htmlを見てみます。
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
という箇所があります。Reactアプリは、この id="root”の要素の子要素として表示されます。
続いて、index.jsを見ていきます。
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
createRootメソッドの第一引数にReactアプリの埋め込み先が指定されています。
また、root.render()の中で<App />というコンポーネントが呼び出されています。これにより配下の<App>コンポーネントを実行してidがrootである要素に描画させることができます。<App>コンポーネントのコードは、App.jsに記述されており、 import './App.js’; とすることで、このコンポーネントを呼び出すことができます。
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>
);
}
export default App;
- import './App.css’; で、この<App>コンポーネントの「見た目」を定義するCSSファイルを読み込んでいます。
- function App() で定義している関数の中のreturn()でAppコンポーネントの表示内容が定義されています。ここでは、以下が表示されるように書かれています。
- Reactのロゴ
- 文字列 Edit <code>src/App.js</code> and save to reload.
- https://reactjs.orgへのリンク
- 最後に、export default App; とすることでAppコンポーネントを他のファイルから呼び出せるようになります。
ここで、<p> </p>の中の文字列を何か別の文字列に書き換えてみてください。エディターなどで編集して保存すると、表示されていたReactのサンプル画面も変更されているのがわかると思います。このようにReactの開発環境では、修正した結果をすぐに画面上で確認することができます。
次にApp.cssを見てみます。
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 50vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
これも少し変更してみましょう。こちらも修正した結果をすぐに画面上で確認することができます。
- background-colorの値を #585c34 に書き換えると、背景色が変わるはずです。
- min-heightの値を 50vhに書き換えると、ブラウザ全面に表示されていたアプリケーション画面が上半分に表示されるようになるはずです。
「宿題」
サンプルコンポーネント「TeamsViewer」を用意しましたので、これをApp.jsから呼び出すように変更してみてください。
/* TeamsViewer.js */
import React, { useState, useEffect } from 'react';
import './TeamsViewer.css';
import TeamList from './TeamList';
function TeamsViewer(props){
const [league, setLeague] = useState(null);
const setAction = () =>{
let element = document.querySelector("#select_league");
setLeague(element.value);
}
return(
<div className="teams_viewer">
<div className="teams_viewer_header">
<select id="select_league">
<option value="1"> J-1 </option>
<option value="2"> J-2 </option>
<option value="3"> J-3 </option>
</select>
<button className="select_button" onClick={(e)=> setAction()}> 選択 </button>
</div>
<div className="teams_viewer_body">
<TeamList league={league} />
</div>
</div>
)
}
export default TeamsViewer;
/* TeamList.js */
import React, { useState, useEffect } from 'react';
function TeamList(props){
const [list_info, setInfo] = useState([]);
useEffect(() => {
if(props.league){
let target = "http://127.0.0.1:8000/api/v1/teams/" + props.league;
fetch(target,{
credentials: "same-origin",
})
.then(response => {
return response.json();
})
.then(result =>{
const txt = JSON.stringify(result, null,' ');
let res = JSON.parse(txt);
setInfo(res);
})
.catch(error =>{
console.error(error);
})
}
},[props]);
if(list_info.length > 0){
return (
<div className="team_list">
<table>
<thead>
<tr>
<th>チーム名</th>
<th>ロゴ</th>
</tr>
</thead>
<tbody>
{list_info.map((team, index)=>{
return(
<tr key={index}>
<td>{team['team_name']}</td>
<td> <img src={team['team_logo']} /> </td>
</tr>
)
})}
</tbody>
</table>
</div>
)
}
}
export default TeamList;
/* TeamsViewer.css */
.teams_viewer {
background-color: #D0D2D2;
}
.teams_viewer_header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 10px;
background-color: #B0B2B2;
}
#select_league {
margin-right: 10px;
font-size: 12pt;
}
.select_button {
margin-left: 10px;
font-size: 12pt;
}
このコンポーネントは、バックエンドサーバーから値を取得しますので、djangoサーバーを起動しておきます。また、次の準備をしてから動作させてください。
(1) ブラウザのクロスオリジン設定を変更
クロスオリジン(Cross-Origin)とは、Webブラウザにおいて、あるWebページ(生成元=オリジン)から、異なるドメイン、プロトコル、またはポート番号を持つ別のサーバーリソースへアクセスすることです。ブラウザはセキュリティ保護のため、異なるオリジン間の通信をデフォルトで禁止しています。(Same-Origin Policy)

開発の際には、この制限をなくすための暫定的な措置を行います。
Safariの場合
・設定 -> デベロッパ
・「クロスオリジンの設定を無効にする」をオンに変更
Google Chromeの場合
・ターミナルを開き、コマンドラインから以下のようにしてChromeを起動する
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --user-data-dir="/tmp/chrome_dev" --disable-web-security