
Reactのコンポーネントの考え方について
Reactではデータを各パーツごとにコンポーネントjsファイルに分割する事で、共有部分の使い回し・管理ができます。
ReactはJSX記法を採用しているので、jsファイルの中にHTMLソースをそのまま記述する事ができます。
分割したjsの関数名と同じタグ名をつける事ができ、コンポーネントを入れ子にする事で階層化部分も分割する事が可能です。
ファイルを分割する
Reactにおけるコンポーネント化とは、ファイル構成を分割して利用する事を指します。
アプリでもWEBサイトでも、ファイルを分離しておく事はとても大切です。
複数パーツに分ける
htmlやjsに限らず、1枚のファイルに長々とコードを記述すると非常に長く複雑になります。
他の人が見た時に、非常にわかりにくいものになってしまいますね。
これらを見やすく管理するため、全体を複数のパーツに分けて構築・管理するのが常識です。
共有部分として使い回す
データを出力する際は、分割したファイルを集約して構成します。
毎回使う部分を「共通パーツ」化する事で「使い回し」ができ、同じ部分を何度も記述せずに済みます。
共有パーツ部分を更新すれば全ページで置き換わってくれるので、格段に更新管理がしやすくなる訳です。
この様に各データは、常に共有パーツ部分ごとに分けておくべきでしょう。
静的サイトならSSI
まずは静的なWEBサイトを例にしてみましょう。
WEBページのHTMLソースには、必ずheaderやfooterのタグエリアがありますよね。
これらは全てのページで共通で使われる部分になります。
この部分はパーツに分けて、共有・使い回しする事ができます。
SSI:サーバーサイドインクルーディング
もしこれらのパーツを静的サイトで分離・共有するなら、「SSI」でしょう。
SSIは「サーバーサイドインクルーディング」の略ですね。
共通パーツ部分を別ファイルに保存しておき、パーツを表示させたい部分に専用タグを置きます。
SSIの構成
HTMLのheader位置に入るタグ
<!#--include file="header.txt" -->
header.txt内ソース
<header> …ヘッダー部分のソース一式 </header>
※SSIを動かすには、.htaccessなどにshtmlの認識記述が必要です。
SSI設定により、header.txt内のソースを「共通パーツ」として表示できます。
ヘッダーやフッターを共通ファイルとして使い回せれば、更新が楽ですよね。
この様な仕組みにしていないと、ヘッダーやフッターに変更があった場合に全ページを更新する必要が出てきます。
SSIの設定の仕方
詳しい設定の仕方については以下の記事を参考下さい。
Wordpressならテーマテンプレート
共有ファイルの分離については、Wordpressの方が理解しやすいかも知れません。
Wordpressのテーマテンプレートは、以下の様に各共通パーツに分けられています。
テーマテンプレートファイル例
header.php(ヘッダー部分)
sidebar.php(サイドバー部分)
footer.php(フッター部分)
index.php(TOPページ部分)
single.php(記事ページ部分)
page.php(固定ページ部分)
Wordpressの構築ファイル拡張子は.phpで、各パーツごとに分離されています。
呼び出し例
ヘッダー読込…<?php get_header(); ?>
フッター読込…<?php get_footer(); ?>
WEBページの表示時に分割された各phpファイルがパーツごとに読みこまれ、ページレイアウトが構成される訳です。
変更が必要な際は、このphpファイルを修正すれば全ページに反映されます。
管理がしやすく便利ですよね。
Reactのファイル構成
前置きが長くなりましたが、いよいよReactです。
Reactは、.htmlや.phpではなく.jsファイルに記述していくシステムです。
つまりほぼ全ての構成が、jsファイル内に記述される訳ですね。
Create React Appのプロジェクト構成
project
├——public(静的ファイル)
│ └─index.html
│ └─manifest.json
│ └─その他
│
├——src(開発フォルダ)
│└─index.js
│ └─その他様々なjsファイル
└package.json
ReactのCreate React Appの環境では、開発用のjsファイルやフォルダは全て「src」フォルダの中に格納されます。
それに対し画像などの静的ファイル群は全て「public」内に入ります。
これらの構成がビルドされる事で、アプリとして動くようになる訳ですね。
軸となるファイルはindex.js
src開発フォルダ内のTOPは、index.jsです。
ReactでのWEBページ制作は、1枚もののSPAページ制作が多いでしょう。
ですがもちろん、マルチページのWEBサイトを構築する事もできます。
いずれの場合も、TOPページとなるこのindex.js内にソースコードを記載する事になります。
JSX記法
本来jsファイル内にHTMLソースを書いても、HTMLファイルとしては動きません。
しかりReactでは実際に動きます。
指定範囲内にhtmlソースを丸ごと入れれば、そのまま表示される様になっています。
それはReactが、「JSX記法」という書き方を採用しているためですね。
これはJavascriptファイルの中で、HTMLタグを記述できる機能です。
JSX記法のおかげで、WEBサイト開発者もReact開発を取り入れやすくなっています。
ですのでReactでは、jsファイルに直接HTMLソースを書き込んでWEBアプリを作る事ができる訳ですね。
Reactでのパーツ分割
Reactではindex.jsを起点にアプリ開発がされていく訳ですが、冒頭でも説明したようにindex.jsに長々とコードは書きません。
静的サイトやWordpessと同様、各パーツを分割して共有・使い回しをしていきます。
それに特化したのが「コンポーネント」機能です。
ReactでWEBサイトのパーツを分割する場合
ReactでWEBページを作るなら、HTMLレイアウトが必ず必要ですよね。
当然index.js内にも、headerやnavi・sectionやfooterなどの各種タグが入ります。
これらのレイアウト部分を別のjsファイルに分割していく訳です。
まずは何も書いていないまっさらな状態のjsファイルを、以下の様にindex.jsと同位置に構成してみましょう。
レイアウトの分割例(src内)
index.js
Header.js
Navi.js
Mainslider.js
Content1.js
Content2.js
Footer.js
分割する際のファイルの拡張子も、もちろん.jsです。
頭文字は大文字が望ましいです。
分割時のルール
Reactでは、コンポーネント化するjsファイルの名前を自由に決める事ができます。
header部分をコンポーネント化するなら、上記の様に「Header.js」としていればどの部分かがすぐにわかりますね。
名前で判別できるように連動させていきましょう。
.jsxを推奨
本来はコンポーネント化している事がすぐわかる様に、分割したファイルの拡張子は「.jsx」にする事が推奨されています。
Header.js→Header.jsx
Footer.js→Footer.jsx
.jsxでも.jsと同じ動きをします。
componentsファイルに入れる
分割したjsファイルの作成位置は同じ階層でも良いのですが、慣例があります。
コンポーネント化したファイルは「components」フォルダの中に入れる事です。
ですので分割した.jsファイルは、components/Header.jsの中に入れましょう。
分割jsファイルをcomponentsに入れた例
├——src
│└─index.js
│└─components
│ └──Header.js
│ └──Navi.js
│ └──Footer.js
※もちろんcomponentsでなく、別の名前で格納しても大丈夫です。
Reactのコンポーネントの書き方
では具体的にReactのコンポーネントの書き方を実践していきます。
まずはcomponentsに入れた、各jsファイルから書き込んでいきます。
分割jsへのソース記述
今回は一例として、Header.js内にHTMLソースのheaderタグ部分を記述します。
components/Header.js
export const header = () => { return ( <> <header> …header内を構成するhtmlソース </header> </> ); };
constの後ろの関数名を、index.js側で読み込む事になります。
export const header = () => {という形で、名前と関数名も揃えます。
同様にFooter.jsであれば、export const footer = () => {と記述します。
return();の中に、<header></header>で囲まれたソースコードをそのまま入れます。
「ファイル名」と「関数名」を揃えていれば、関数名からjsファイルの名前がわかるので同じものにした方が良いです。
同じ要領でSide.jsやFooter.jsなど、分割したjsファイル全てに関数名と分割ソース部分を入れておきます。
index.jsの記述
分割js側の設定が終わったら、index.js側で分割したjs群を読み込みます。
以下はヘッダーやサイドバー、フッター部分のjsを読み込む場合の例です。
index.jsの記述
import ReactDOM from "react-dom"; import { header } from "./components/Header"; import { side } from "./components/Side"; import { footer } from "./components/Footer"; const App = () => { return ( <> <header /> <side /> <footer /> </> ); }; ReactDOM.render(<App />, document.getElementById("root"));
2行目でそれぞれの.js内に記述した、関数名の情報を読み込んでいます。
それがApp関数内の<header />タグら3つに出力されます。
これにより、Header.jsやSide.js・Footer.js内のソース部分が流れ込んできますね。
コンポーネント化のメリット
上の項目でさらっと説明しましたが、ここにReactの大きな特徴であり重要な点があります。
それは「関数名と同じ名前でタグ付けができる」事です。
関数名同じタグを使える
例えば以下の様に、分割したjsの関数名とindex.jsの読込タグは揃っています。
Header.js内のheader関数→index.js内の<header />
Footer.js内のfooter関数→index.js内の<footer />
Side.js内のside関数→index.js内の<side />
上記は想起しやすいタグ名なので、違和感がないかも知れませんね。
Lpeg.jsの場合
では例えばcomponents/Lpeg.jsというjsファイルを作ったとしましょう。
関数名はjs名に揃えた方が良いので、関数部分はlpegになります。
これをindex.jsで読み込む場合、<lpeg />という専用タグが使える訳です。
Christmas.js(関数名christmas)なら…<christmas />のタグ
Fukuoka.js(関数名Fukuoka)なら…<fukuoka />のタグ
決めたjsの名前に応じて同じ名前のタグが使えるので、視覚的にわかりやすくなりますね。
WEBサイトを全てコンポーネント化する
ではWEBサイトのすべての部分をコンポーネントで分割してみましょう。
WEBサイトの構成例
例えば以下の様なWEBページ構成があったとします。
<header>
・ロゴ表示部分
・上部TEL番号部分
・ナビゲーション部分
</header>
<section class="mainslider">
・メインスライダー部分
</section>
<section>
・メインコンテンツ1
</section>
<section>
・フロートコンテンツ1
・フロートコンテンツ2
・フロートコンテンツ3
</section>
<footer>
・フッターロゴ部分
・フッターメニュー部分
・copyright部分
</footer>
上記のページレイアウト構成を、全てjsファイルに分けます。
その時のパーツjsの名前と、中で使う関数の名前をきちんと揃えましょう。
生成タグとjs名の一覧
生成されたタグの一覧と各jsファイルは以下の様に連動します。
<header />…components/Header.js
<logo />…components/Logo.js
<toptel />…components/Toptel.js
<navi />…components/Navi.js
<mainslider />…components/Mainslider.js
<section1 />…components/Content1.js
<section2 />…components/Content2.js
<float1 />…components/Float1.js(横並びコンテンツ)
<float2 />…components/Float2.js(横並びコンテンツ)
<float3 />…components/Float3.js(横並びコンテンツ)
<footer />…components/Footer.js
<footerlogo />…components/Footerlogo.js
<footermenu />…components/Footermenu.js
<copyright />…components/Copiright.js
使い回しは自由
コンポーネントタグは、いつでもどこでも自由に使い回せます。
<header />や<footer />などは、他のページでも共通で読み込みするようになるでしょう。
タグ名からファイル名がすぐにわかるので、メンテナンス時も抜群の管理能力を発揮します。
コンポーネントの入れ子
上でかなりの量のコンポーネント群が並んでいましたが、実はこれらをindex.jsで全て読み込む必要はありません。
階層化されている部分は、階層元の「親」となるコンポーネントファイルで読み込めば良いのです。
つまりコンポーネントを「入れ子」にしていく訳ですね。
階層元で入れ子にする
例えばheaderのタグ内には、以下の3つの要素が入っていましたよね。
<header>
・ロゴ表示部分
・上部TEL番号部分
・ナビゲーション部分
</header>
これらをコンポーネントファイル上で示すと、Header.jsが親であり下の3つのjsが子になります。
components/Header.js…親
components/Logo.js…子
components/Toptel.js…子
components/Navi.js…子
Header.js内のコンポーネントの入れ子記述
では親のHeader.js内の記述を、以下の様に書き換えます。
import { logo } from "./components/Logo"; import { toptel } from "./components/Toptel"; import { navi } from "./components/Navi"; export const header = () => { return ( <> <logo /> <toptel /> <navi /> </> ); };
最初にimportで3つのコンポーネントファイルを読み込みます。
子であるロゴやTEL番号・ナビゲーションのjsに、headerを構成するソース部分をきれいに分けました。
全て子のjsが担当しているので、Header.jsで直接読むHTMLソース部分は無いのです。
WEBレイアウトを入れ子で構成
同様にFooter.jsでは、フッターロゴ・フッターナビ・コピーライトの要素を入れ子にできます。
Content2.js内でも階層下に3つの横並びボックス要素が入るので、この3つを入れ子にする事ができますね。
こうして入れ子にしていくと、index.jsで読み込むのは「親ファイルのみ」になります。
入れ子後のindex.js記述例
import ReactDOM from "react-dom"; import { header } from "./components/Header"; import { mainslider } from "./components/Mainslider"; import { section1 } from "./components/Content1"; import { section2 } from "./components/Content2"; import { footer } from "./components/Footer"; const App = () => { return ( <> <header /> <mainslider /> <section1 /> <section2 /> <footer /> </> ); }; ReactDOM.render(<App />, document.getElementById("root"));
index.jsでimportされているコンポーネントは、限定的である事がわかりますよね。
自分が読み込んでいるファイル以外の事を気にする必要が無い訳です。
headerやfooter、section2については、自分が入れ子にしているコンポーネントデータだけを見ればいい訳です。
まとめ:コンポーネントは細分化可能
Reactのコンポーネントの特徴をまとめてみました。
・jsファイルの中にHTMLタグが書ける事
・jsファイルの関数名と同じタグが作れる事
・コンポーネントは入れ子にできる事
Reactのコンポーネントの仕組みは、作りやすさと管理のしやすさを兼ね備えたものになっていると思います。
どんな短いコードでもコンポーネント化できる
今回はレイアウトを分割してコンポーネント化しましたが、もっと自由に細かくできます。
1行の文章部分だけでも、コンポーネントに分ける事ができる訳です。
実際には親コンポーネントファイルからその部分を分割し、入れ子にする訳ですね。
どの部分をどう分けるのかについては、サイトの設計次第となるでしょう。