React使ってSPAを作るよ(8)の続きです。
若干脱線していましたが、やっとReactに戻ります。
JSXファイルを分割する
さて、これまでJSXファイルはapp.jsxのみでした。
このファイルにコンポーネントを複数書いて、最後にレンダリングしていましたが、これだとサイト内で使うパーツを全部ここに入れることになっちゃいます。
修正するときに大変。
チームで作業するときなんか、同時に触りづらいし、できればヘッダ、フッタとか、コンテンツも○○のリストとかパーツごとに修正しやすいようにファイルを分けたいですね。
そこで今回は、ヘッダ、フッタ、記事リストのコンポーネントをそれぞれ別のJSXファイルにして、最後にapp.jsxで呼び出すように変更していきます。
たとえば、フッタのみのファイルを作るとします。
//SiteFooter.jsx
var React = require('react');
//サイトフッタコンポーネント
var SiteFooter = React.createClass({
render: function() {
return (
<footer id="common-footer">
<h2>フッタ</h2>
<address>連絡先とか</address>
<p>コピーライト</p>
</footer>
);
}
});
module.exports = SiteFooter;
一番下の行、今までにないものがでてきました。
これはSiteFooterをほかのJSXファイルで使えるようにするために必要なので、最終的に呼び出すコンポーネントをここで指定しておきます。
また、app.jsxでは、
var React = require('react');
var SiteFooter = require('./SiteFooter.jsx');
//略
といった具合に読み込んでおきます。
あとは普段通りに親コンポーネントに入れてレンダリングです。
//bodyコンポーネント
var Body = React.createClass({
render: function() {
return (
<div id="container">
<SiteHeader />
<Main />
<SiteFooter />//これがSiteFooter.jsxから読み込んだコンポーネント
</div>
);
}
});
/* React + JSX */
React.render(
<Body />,
document.getElementById('body')
);
なんか急にbodyになってるじゃねーか!と思った方、そうです、実を言うと要素の構造を変更しました(;´∀`)
ファイルを分割したり、コンポーネントを複数用意しても、最終的にコンポーネントが返す要素は「1要素」でないといけません。
この制約だと
//bodyコンポーネント
var Body = React.createClass({
render: function() {
return (
<SiteHeader />
<Main />
<SiteFooter />
//3要素だからダメ!
);
}
});
こういう書き方でbodyに入れることもできないし、
/* React + JSX */
React.render(
<SiteHeader />,
<Main />,
<SiteFooter />,
//3要素だからダメ!
document.getElementById('body')
);
こういう書き方で最後にまとめてレンダリングすることもできません。
がっかり(´・ω・`)
そこでindex.htmlは
<body> <div id="body"></div> <button type="button" id="overlay"></button> <script src="/js/jquery-2.2.0.min.js"></script> <script src="/js/common.js"></script> <script src="/js/bundle.js"></script> </body>
こんなふうに、ヘッダ・フッタ・メインコンテンツをすべて突っ込むためのdiv#bodyを用意しました。
できれば文書構造にもスタイリングにも関係ないdivは入れたくないし、body要素内に直接レンダリングしたいけど、そうするとbundle.jsを読み込むためにはdivとかの中に入れざるを得ないんですよねぇ…(;´Д`)
それもちょっとどうだろうと思ったのでこうしました。
記事リストをメインコンテンツに入れる
さて、同じ要領でArticleAreaを別ファイルにして読み込もうと思うのですが、このメインコンテンツ部分はこれからほかのパーツが入ったりするかもしれませんよね。
記事リストのパーツはそれだけで管理して、ほかのパーツが増えたらそれも別ファイルで管理したいです。
そこで、ArticleArea.jsxは
//ArticleArea.jsx
var React = require('react');
//略
//記事リストコンポーネント
var ArticleArea = React.createClass({
//JSONデータ取得
//略
render: function() {
var articleNodes = this.state.data.map(function(article) {
return (
<ArticleList articleTag={article.tagData} articleMark={article.markData} articleComment={article.commentData} articleTitle={article.articleTitle} articleUrl={article.articleUrl} articleDescription={article.articleDescription} articleImage={article.articleImage} />
)
});
return (
<ul id="article-list">
{articleNodes}
</ul>
)
}
});
module.exports = ArticleArea;
あくまでも記事リストのulのみをコンポーネント化して呼び出せるようにしておきます。
これでこの記事リストがメインコンテンツに入ろうが、別のページに使われようが問題なくなりますね。
そしてapp.jsx側でmain要素のコンポーネントを作ります。
//app.jsx
var React = require('react');
var SiteHeader = require('./SiteHeader.jsx');
var ArticleArea = require('./ArticleArea.jsx');
var SiteFooter = require('./SiteFooter.jsx');
//メインコンポーネント
var Main = React.createClass({
render: function() {
return (
<main className="wrap">
<ArticleArea />
</main>
);
}
});
//bodyコンポーネント
var Body = React.createClass({
render: function() {
return (
<div id="container">
<SiteHeader />
<Main />
<SiteFooter />
</div>
);
}
});
/* React + JSX */
React.render(
<Body />,
document.getElementById('body')
);
こうしておけば、main要素に記事リスト以外のものも呼んでくることができます。
このmain要素も今回作ったのでこれまでのモックとは異なりますが、React使ってSPAを作るよ(4)で用意していたdiv#containerだったところが、main要素になったと思ってください。
最新のHTML/CSS/JSのモックは次回用意しますね!
残るはヘッダです。
//SiteHeader.jsx
var React = require('react');
//サイトヘッダコンポーネント
var SiteHeader = React.createClass({
render: function() {
return (
<header id="common-header">
<h1>ヘッダh1</h1>
</header>
);
}
});
module.exports = SiteHeader;
たったこれだけ。
わざわざコンポーネントにする必要あるの?と思うかもしれませんが、headerの中に入るのはh1だけとは限らないんですよね。
ここにフォームの新規パーツを追加したいと思います。
次回はモックにフォームを追加して、JSXファイルのネストをしたいと思います!