Next.jsでの開発の進め方
さて、順番が前後する形になりましたが、ここからはNext.jsを用いて、ローカル環境で開発を行う方法について解説していきます。
前回と今回のサンプルコードであるfirebase-ssrにおいて、package.jsonは、リスト3のようなdependenciesを持っています。
"dependencies": {
"firebase-admin": "^5.12.1",
"firebase-functions": "^1.0.2",
"next": "^6.1.2",
"react": "^16.5.1",
"react-dom": "^16.5.1"
},
これらのうち、Next.jsを動かすために最低限必要なパッケージは、 react 、 react-dom 、 next の3つです。 firebase- で始まるパッケージは、Firebase Cloud FunctionsやFirebase Hostingのためにインストールされているので、Next.jsを使うために必要なわけではありません。
nextパッケージには、アプリケーション内でインポートするためのモジュールだけではなく、実行用のコマンドも含まれています。package.jsonのscriptsを見てみましょう(リスト4)。
"scripts": {
"dev": "next \"src/app/\"",
npm scriptsとして、 dev コマンドで next "src/app" コマンドが登録されています。これが、開発サーバーを起動してデバッグを行うためのコマンドです。create-react-appで作ったプロジェクトでいえば、 npm start に相当するものになります。
今回のサンプルでは、Next.js製アプリケーションを src/appフォルダに格納しているため、 next コマンドにコマンドライン引数として "src/app" が渡されています。もしプロジェクトのルート直下に pages/ や static/ といったフォルダ(後述します)を配置している場合は、コマンドライン引数無しで、ただ next を実行してデバッグをすることも可能です。
開発サーバーを起動する
それでは実際に、開発サーバーを起動してみましょう。すでに紹介している通り、devコマンドを実行します。
$ npm run dev
すると、ターミナルが図7のような表示になります。
ここで現れた http://localhost:3000 を、ブラウザで開くと、図8のような表示になります。
いい感じですね。「Home」や「About」のリンクをクリックすると、ちゃんとページが切り替わります。
実際の開発では、ここにReactアプリケーションを構築していくことになります。
Next.jsの基本:フォルダの役割
動かし方がわかってきたところで、Next.jsでアプリケーション開発を行うときの基本的なお作法と、よく使う機能について解説していきます。
本連載で主に扱ってきたcreate-react-app製のプロジェクトでは、「エントリーポイントであるsrc/index.jsで ReactDOM.render() さえ実行していれば、あとは自由にフォルダを構成してよい」といった緩いルールでアプリケーションを作成することができました。
一方で、Next.jsは少し毛色が異なっており、決まった役割を持ったフォルダがあります。pagesとstaticです。
画面を格納するpagesフォルダ
Next.jsプロジェクトのルートディレクトリに、pagesという名前のフォルダを作成し、その中にReactコンポーネントのファイル(例えば、src/app/pages/hoge.js)を定義すると、次のような挙動をします。
-
/hogeというURLのパスが作成される -
/hogeに、hoge.jsからexport defaultで公開されたコンポーネントが割り当てられる
これらの設定が、自動で行われます。第5回では、react-routerを用いて、URLのパスとコンポーネントをつなぎ合わせていましたが、Next.jsではそれが不要になります。
サンプルコードでも、src/app/pagesの中に2つのコンポーネントが定義されていますね(図9)。
これらがそれぞれ、図8で表示していたHome(/)とAbout(/about)という2つのページになっていたわけです。
ホームページ制作や、それにインタラクティブな操作を少し追加するくらいでは、複雑な画面遷移は必要ないので、こういった手軽さは重宝しますね。
画面間の移動については、後述します。
静的ファイルを配信するstaticフォルダ
もう1つの名前が決まっているフォルダとして、staticがあります。これは、静的ファイルを格納しておくと、 /static 以下のパスで静的ファイルにアクセスさせてくれるものです。
例を挙げてみましょう。サンプルのpagesフォルダの隣にstaticフォルダを作り、アイコンを入れておきます(図10)。
そして、コンポーネント側から参照する際にはリスト5のようになります。
export default () => (
<App>
<p>About Page</p>
<img src="//cz-cdn.shoeisha.jp/static/emoticon.png" /> {/* (1) */}
</App>
)
(1)では、相対パス等ではなく /static で始まる絶対パスで参照しています。もちろんこれは問題なく表示されます(図11)。
階層が深まりがちなコンポーネントの中で、画像ファイル等を扱う際には、絶対パスで参照できたほうが便利です。これが標準で使えるのもまた、Next.jsのうれしい点ですね。
ルーティング
画面の定義は、pagesフォルダにコンポーネントを配置するだけで完結するという解説を行いました。では、画面間の移動はどのように行えばよいでしょうか。
大別して、 <Link> コンポーネントを使った方法と、 Router.push() を使った方法の2つがあります。第5回で解説したreact-routerと似通った部分もありますが、それぞれ解説します。
<Link> を使った方法
まずは、「クリックしたら画面遷移」という通常のaタグの挙動で画面遷移を行うための、 <Link> コンポーネントを用いた方法です。サンプルコードでいうと、ヘッダーでHome画面とAbout画面を切り替えているところの実装で使われています(リスト6)。
import * as React from 'react'
import Link from 'next/link'
import { withRouter } from 'next/router';
const Header = ({ router }) => ( {/* (3) */}
<header>
<Link href='/'> {/* (1) */}
<a className={router.pathname === '/' ? 'is-active' : ''}>
Home
</a>
</Link>
{' '}
<Link href='/about'>
<a className={router.pathname === '/about' ? 'is-active' : ''}>
About
</a>
</Link>
</header>
);
export default withRouter(Header); {/* (2) */}
(1)のように、href属性でパス文字列を指定することで、遷移先を指定できます。リスト6では子要素にaタグを記述していますが、ここはimgタグ等、別のものを配置しても問題ありません。
なお、(2)のようにwithRouter関数を通してからコンポーネントを外部に公開することで、(3)のように router をpropsとして受け取れます。 router には、URL上の現在のディレクトリである pathname や、クエリパラメータである query が格納されており、URLを元に挙動を変えたい場合には便利です。
Router.push() を使った方法
こちらは直接のUI操作ではなく、内部処理のどこかで動的に画面遷移を発生させたい場合に用いる方法です。リスト7のように使用します。
import Router from 'next/router'
export default () => (
<div>
Click <span onClick={() => Router.push('/about')}>here</span>
</div>
);
next/router モジュールから取り出したRouterからpush関数を呼び出し、引数に遷移先のパスを渡しています。
まとめ
Next.jsをFirebaseの各種サービスにデプロイする、基本的な使い方についてレクチャーを行いました。Webサイトの構築に便利な機能が標準で備わっているのが、とてもうれしいところです。
さて、今回で本連載は最終回となります。Reactを活用したWebアプリケーションやWebサイトの制作手法やツールを、いろいろと紹介してきました。Reactはパワフルかつシンプルなツールです。自分に必要な分だけのツールを取捨選択して、便利に使っていきましょう。
