はじめに
はじめに、筆者はWeb開発初心者です。ついでに学生です。間違った内容を提示してしまうことがあるかもしれませんが、その際は指摘してくれるとありがたいです。
Web開発は難しい
私がこの記事を書く理由でもありますが、Webページを作るというのは意外と難しいです。ひと昔前ではHTMLとCSSが書ければWebページとしての体裁は整いました。しかし、用途の多様化に伴い、静的なページからHTMLを自己編集する動的なページへと需要が移り、必要な知識と技術が爆発的に増えました。それに伴って、Ruby on RailsやPlay Frameworkが生まれたのです。これは10年以上前の話ですが最近はどうでしょうか。よく挙げられるフレームワークとしてAngular、React、Vue.jsがありますが、これらが2013年頃から出てきました。さて、例をいくつか挙げましたが初心者は何を使えばいいでしょうか?私は分かりません。諺でいう、亡羊の嘆ってやつです。
とりあえずReactするかぁ~
Reactって何?
Reactをはじめる前にどんな設計思想をもったツールなのかを考えたいと思います。
###コンポーネント
Reactに限った話ではありませんが、ある機能を実装するとき、細かく分割したコンポーネントと呼ばれる部品を組み合わせて実現させており、コード再利用性の向上やメンテナンスを容易にすることができます。しかし、実装の際には親コンポーネントから子コンポーネントへのオブジェクトの引き渡し(props)やコンポーネント内での状態の管理(state)、それらを踏まえたコンポーネントのライフサイクルを考慮する必要があります。
Virtual DOM
次にVirtual DOM(Document Object Model)という概念について説明したいと思います。ちなみに、Virtual DOMはVueにも採用されています。
DOMはいわゆる、ブラウザ表示に使われるhtmlの構造を見て制御を行うAPIです。ここで考えるべきなのは、あるコンポーネント処理の結果としてDOMの変更が起こる時です。このとき毎回DOMを一から生成するにはブラウザ表示に遅延が生じることが考えられます。そこで表示するDOMを生成し直さずに一旦Virtul DOMというものを生成し、Virtul DOMを更新しつつ、表示するDOMとの差分のみを更新することで表示の遅延をなくします。
React以前の環境構築
別の記事にTypeScriptやnpm関連の導入の仕方は書いたので、こちらを読んでください。
TypeScriptをはじめよう 1
Reactをはじめる
Reactをはじめる前に、React自体にはテンプレートを生成する機能はありません。そのため、以下のオンラインエディタを使うかFacebookから提供されるcreate-react-appを使います。
今回は自前の環境で開発を進めたいので、オンラインエディタは使いません。では、以下のコマンドを適当なディレクトリで行なってください。
npm install -g create-react-app
create-react-app <プロジェクト名> --typescript
次にcreate-react-appがyarnを推奨しているのでyarnを導入します。yarnはnpmと同じくパッケージ管理ツールです。
npm install -g yarn
では、プロジェクトのディレクトリに移って以下のコマンドを実行しましょう。
yarn start
これでブラウザが立ち上がり、以下の画面が映れば問題ありません。
React TSX
ブラウザに表示されていますが、src/App.tsxを編集することでページを編集することができます。TSXはJSXのTypeScript版で、HTMLライクな記述を可能にしたTypeScriptの拡張です。とりあえず、説明しやすいように簡単な成績表示をするページを考えます。サンプルコードは以下です。
import React from 'react';
import './App.css';
const App: React.FC = () => {
const tdata = [
{name: "Aさん", japanese: 68, math: 75, social: 74, socience: 48, english: 70},
{name: "Bさん", japanese: 90, math: 43, social: 80, socience: 55, english: 76},
{name: "Cさん", japanese: 53, math: 64, social: 54, socience: 64, english: 38}
]
return (
<div>
<h1> 点数表 </h1>
<table className= "studentAchive">
<tbody>
<tr>
<td>{"名前"}</td><td>{"国語"}</td><td>{"数学"}</td><td>{"社会"}</td><td>{"理科"}</td><td>{"英語"}</td>
</tr>
<tr>
<td>{tdata[0].name}</td><td>{tdata[0].japanese}</td><td>{tdata[0].math}</td><td>{tdata[0].social}</td><td>{tdata[0].socience}</td><td>{tdata[0].english}</td>
</tr>
<tr>
<td>{tdata[1].name}</td><td>{tdata[1].japanese}</td><td>{tdata[1].math}</td><td>{tdata[1].social}</td><td>{tdata[1].socience}</td><td>{tdata[1].english}</td>
</tr>
<tr>
<td>{tdata[2].name}</td><td>{tdata[2].japanese}</td><td>{tdata[2].math}</td><td>{tdata[2].social}</td><td>{tdata[2].socience}</td><td>{tdata[2].english}</td>
</tr>
</tbody>
</table>
</div>
);
}
export default App;
気づいただろうか?これはクソプログラムです。
では、これをもう少しまともなプログラムに直していきましょう。ブラウザ上では、以下のように表示されます。
コンポーネントの細分化
このプログラムの問題点を挙げると、このプログラムには汎用性がありません。例えば、現在使われている成績は3人分のデータを使っていますが、これを30~40人程度の1教室分や更に多い1学年分を表示するとした場合はどうでしょう。はっきり言えば面倒ですね。Webアプリに限らず、プログラムを機能ごとに切り出して考えることは必要不可欠です。それでは、このコードを改善していきましょう。
propsとかいうやつ
先にコードだけ載せます。
import React from 'react';
import './App.css';
interface propsType {
name: String,
japanese: Number,
math: Number,
social: Number,
socience: Number,
english: Number,
}
const Td:React.FC<propsType> = (props) => {
return(
<tr>
<td>{props.name}</td><td>{props.japanese}</td><td>{props.math}</td><td>{props.social}</td><td>{props.socience}</td><td>{props.english}</td>
</tr>
);
}
const App: React.FC = () => {
const tdata = [
{name: "Aさん", japanese: 68, math: 75, social: 74, socience: 48, english: 70},
{name: "Bさん", japanese: 90, math: 43, social: 80, socience: 55, english: 76},
{name: "Cさん", japanese: 53, math: 64, social: 54, socience: 64, english: 38}
]
return (
<div>
<h1> 点数表 </h1>
<table className= "studentAchive">
<tbody>
<tr>
<td>{"名前"}</td><td>{"国語"}</td><td>{"数学"}</td><td>{"社会"}</td><td>{"理科"}</td><td>{"英語"}</td>
</tr>
{
Array.from(tdata).map(
(data:propsType) => <Td name={data.name} japanese={data.japanese} math={data.math} social={data.social} socience={data.socience} english={data.english}/>
)
}
</tbody>
</table>
</div>
);
}
export default App;
追加したのはこの部分と
interface propsType {
name: String,
japanese: Number,
math: Number,
social: Number,
socience: Number,
english: Number,
}
const Td:React.FC<propsType> = (props) => {
return(
<tr>
<td>{props.name}</td><td>{props.japanese}</td><td>{props.math}</td><td>{props.social}</td><td>{props.socience}</td><td>{props.english}</td>
</tr>
);
}
この部分
{
Array.from(tdata).map(
(data:propsType) => <Td name={data.name} japanese={data.japanese} math={data.math} social={data.social} socience={data.socience} english={data.english}/>
)
}
propsは親コンポーネントから子コンポーネントに値や関数を渡す方法です。型はinterfaceで宣言して使います(宣言しないとエラー起こす)。また、propsの引き渡しはHTMLの属性のようにかくことができます。
おわり
最後の方がだいぶ雑になったこととState、ライフサイクルの話がなくて申し訳ないです。まだ自分の理解が至っていないこととあまり間違った内容を載せたくないという気持ちでこうなってしまいました。次はもう少し頑張ります。