現代のウェブ開発シーンは、JavaScriptのライブラリやフレームワークに事欠くことがありません。中でも人気のライブラリの1つがReactです。Facebook(現Meta)が機能豊富なアプリケーション構築を支援するために開発しました。Reactアプリケーションは従来、ウェブブラウザ上で動作するものですが、Next.jsフレームワークは、JavaScriptランタイム環境Node.jsを通じてReactの機能をサーバサイドに拡張する存在です。

この記事では、Next.jsとReactの役割や用途などについてご紹介します。

Next.JsとReactについての動画での説明もご用意しています

Next.jsとReact─JavaScriptを次のレベルに

2022年のSlashDataの調査によると、世界中に1,700万人以上のJavaScriptプログラマーがおり、PythonやJavaのような人気言語に差をつけていることがわかります。JavaScriptはクライアント側とサーバー側の両方で使用できるため、1つのプログラミング言語を使って本格的なアプリケーションを構築可能です。

 2022年にプログラマーが使用する言語についてのSlash/Dataの調査
2022年にプログラマーが使用する言語についてのSlash/Dataの調査(画像参照元:Statista

ReactのようなJavaScriptライブラリやNext.jsのようなフレームワークの登場が、その開発力をさらに高めることになりました。これらのライブラリやフレームワークは、フロントエンドとバックエンドの統合を簡素化してくれます。さらに、npm(Node.jsのパッケージマネージャ)のようなパッケージマネージャを使ってJavaScriptの機能を拡張し、JavaScriptのライブラリやツールをインストールできます。各種リソースは、自分で書かなければならないコードの量を減らす上で欠かせない存在です。

JavaScriptの拡張性には目を見張るものがあります。これについて包括的な知識を獲得することで、ウェブ開発者としての成功に近づくことができるはずです。

Next.jsとは

Next.jsは2016年にVercel社からリリースされました。高性能なウェブアプリケーションの構築を支えるオープンソースのReactフレームワークです。Twitch、TikTok、Uberなど、世界の有名企業が採用しています。

Next.jsは、高速でSEOに強いアプリケーションの構築に向いています。Next.jsが優れたプロダクションフレームワークであることを示す特徴をいくつかご紹介します。

  • ハイブリッドレンダリング機能
  • 自動コード分割
  • 画像の最適化
  • CSSプリプロセッサとCSS-in-JSライブラリのビルトインサポート
  • ルーティング機能

これらの機能により、Next.jsを使って、設定や調整にかかる時間を大幅に短縮することができます。例えば、次のようなプロジェクトのアプリケーションの構築に、すぐに取りかかることが可能です。

  • EC/オンラインストア
  • ブログ
  • ダッシュボード
  • シングルページアプリケーション
  • インタラクティブなユーザーインターフェース
  • 静的サイト

Reactとは

Reactは、動的なユーザーインターフェースの構築に便利なJavaScriptライブラリです。ウェブインターフェースだけでなく、React Nativeを使ってモバイルアプリケーションを構築することも可能です。

Reactを使用するメリットとしては、以下のようなものがあります。

  • パフォーマンスの向上:Reactでは、DOM内の全コンポーネントを毎回編集する代わりに、仮想DOMを使用し変更の必要なコンポーネントのみが更新されます。
  • コンポーネントベース:一度作成してしまえば、コンポーネントを繰り返し利用することができます。
  • デバッグが容易:Reactアプリケーションでは、親コンポーネントから子コンポーネントへ、一方向のデータフローが採用されています。

Next.jsとReactの比較

Next.jsとReactは同じような目的で使われることが多いのですが、両者には基本的な違いがあります。

使いやすさ

Next.jsもReactも、比較的簡単に使い始めることができます。それぞれ、Node.jsのnpmの一部であるnpxを使って、ターミナルで1つのコマンドを実行するだけでOKです。

Next.jsの場合、最もシンプルなコマンドは次のとおりです。

npx create-next-app

create-next-app では、追加の引数を使うことなく、対話形式でインストールを進めることができます。プロジェクト名(プロジェクトディレクトリに使用されます)と、TypeScriptとコードリンターESLintのサポートが必要かどうかが尋ねられます。

具体的には、以下のように表示されます。

インタラクティブモードでNext.jsアプリケーションを作成する
インタラクティブモードでNext.jsアプリケーションを作成する

Reactインスタンスの初期化について言えば、もっともシンプルなコマンドは以下のようになります。プロジェクトのディレクトリ名を指定しています。

npx create-react-app new-app

これによって、必要な初期設定と依存関係をすべて含むフォルダが生成されます。

ターミナルのコマンドラインからReactプロジェクトを作成する
ターミナルのコマンドラインからReactプロジェクトを作成する

どちらも簡単に始められますが、大事な点としてNext.jsはReact上に構築されています。つまり、Next.jsを使いこなすためには、Reactを学びその仕組みを理解する必要があります。とは言え、Reactの学習は決して難しくありません。

また、Reactはある意味で、非構造的であることにも注意が必要です。Reactのルーターをインストールして設定し、データの取得、画像の最適化、コードの分割をどのように処理するかを決定する必要があります。このセットアップには、追加のライブラリやツールのインストールと設定が必要になります。

これに対してNext.jsでは、各種ツールがあらかじめインストールされ、必要な設定も行われます。Next.jsでは、pagesフォルダに追加されたファイルは、自動的にルートとして機能します。この機能により、Next.jsはアプリケーションのロジックの面で使いやすさがあり、すぐにコーディングに着手することができます。

Next.jsとReactの特徴

Next.jsがReactをベースにしているという性質上、両者は必然的にいくつかの機能を共有しています。それを踏まえた上で、Next.jsではさらに一歩進んで、ルーティング、コード分割、プリレンダリング、APIサポートなどの機能をすぐに利用することができます。これらは、Reactでは自分で設定する必要があります。

データのフェッチ

Reactは、クライアント側でデータをレンダリングします。サーバーからブラウザに静的ファイルを送信し、ブラウザがAPIからデータを取得してアプリケーションに反映させます。このプロセスは、アプリのパフォーマンス低下を招く可能性があります。アプリの読み込みが遅いと、ユーザーエクスペリエンスに悪影響が出ます。一方でNext.jsは、プリレンダリングによってこの問題を解決しています。

プリレンダリングでは、ブラウザへのアプリケーション送信の前に、サーバーが必要なAPIコールを行い、データを取り込みます。そのため、ブラウザにはすぐにレンダリング可能なウェブページが送り届けられます。

プリレンダリングは、静的サイトレンダリング(SSG)またはサーバーサイドレンダリング(SSR)を指すことがあります。SSGでは、HTMLページはビルド時に生成され、複数のリクエストに繰り返し利用されます。Next.jsでは、データのあるHTMLページも、データのないHTMLページも生成することができます。

以下は、Next.jsがデータなしのページを生成する例です。

function App() {
  return <div>Welcome</div>
}
export default App

外部データを利用する静的ページには、getStaticProps()関数を利用します。ページからgetStaticProps()をエクスポートすると、Next.jsはそれが返すpropsを利用して、ページをプリレンダリングします。この関数は常にサーバー上で動作します。そのため、ビルド時にページが使用するデータが利用可能な場合にgetStaticProps()が使用されます。たとえば、CMSからブログ記事を取得する場合などに利用できます。

const Posts= ({ posts }) => {
    return (
        <div className={styles.container}>
            {posts.map((post, index) => (
                // render each post
            ))}
        </div>
    );
  };

export const getStaticProps = async () => {
    const posts = getAllPosts();
    return {
        props: { posts },
    };
};

ページパスが外部データに依存している状況では、getStaticPaths()関数を使用します。つまり、投稿IDに基づいたパスを作成するには、getStaticPaths()をページからエクスポートすることになります。

例えば、以下のように「pages/posts/[id].js」からgetStaticPaths()をエクスポートします。

export getStaticPaths = async()  => {
  // Get all the posts
  const posts = await getAllPosts()

  // Get the paths you want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))
  return { paths, fallback: false }
}

getStaticPaths()は多くの場合、getStaticProps()と対になります。この例では、getStaticProps()を使って、パスの中のIDの詳細情報を取得しています。

export const getStaticProps = async ({ params }) => {
    const post = await getSinglePost(params.id);
    return {
        props: { post }
    };
};

SSRでは、データが要求された時点で取得され、ブラウザに送信されます。SSRを使用するには、レンダリングしたいページからgetServerSide() props関数をエクスポートします。サーバーはリクエストごとにこの関数を呼び出すので、SSRは動的なデータを用いたページで有効です。

例えば、ニュースAPIからデータを取得するのに使うことができます。

const News = ({ data }) => {
    return (
        // render data
    );
  };

export async function getServerSideProps() {
    const res = await fetch(`https://app-url/data`)
    const data = await res.json()
    return { props: { data } }
}

データがリクエストごとに取得され、propsを介しNewsコンポーネントに渡されます。

コードの分割

コード分割は、コードを小分けにすることを意味します。これにより、ブラウザで必要に応じてロードできるようになります。サーバーからは、ユーザーが必要とするものだけが送信されるため、最初の読み込み時にブラウザに送信されるコードの量を減らすことができます。Webpack、Rollup、Browserifyなどのバンドルで、Reactのコード分割がサポートされています。

Next.jsは、コード分割にデフォルトで対応しています。

Next.jsでは、各ページのコードが分割され、アプリケーションにページを追加してもバンドルサイズが大きくなることはありません。また、JavaScriptモジュールをインポートして、実行時に動的に読み込むことができる動的インポートをサポートしています。動的インポートは、バンドルの遅延読み込みにつながるためページの高速化に貢献します。

たとえば、下のHomeコンポーネントでは、Heroコンポーネントを最初のバンドルに含めないようにしてしています。

const DynamicHero = dynamic(() => import('../components/Hero'), {
  suspense: true,
})

export default function Home() {
  return (
    <Suspense fallback={`Loading...`}>
      <DynamicHero />
    </Suspense>
  )
}

上にあるように、Suspenseのフォールバック要素が、Heroコンポーネントの読み込みの前にレンダリングされます。

Next.jsとReactのAPIサポートの比較

Next.jsでは、APIルーティング機能により、バックエンドとフロントエンドのコードを同じコードベースで記述することができます。pages/api/フォルダに保存されたページはすべて/api/*ルートにマップされ、Next.jsはこれをAPIエンドポイントとして扱います。

たとえば、pages/api/user.jsというAPIルートを作成すると、このように現在のユーザー名が返されます。

export default function user(req, res) {
    res.status(200).json({ username: 'Jane' });
}

https://app-url/api/userのURLにアクセスすると、usernameオブジェクトが表示されます。

{
        username: 'Jane'
}

APIルートは、アクセスしているサービスのURLを隠したい場合や、バックエンドアプリケーション全体をコーディングせずに環境変数を秘密にしておきたい場合に便利です。

パフォーマンス

Next.jsは、シンプルなプロセスでパフォーマンスの高いアプリを作成できる点で優れていることは間違いありません。SSRおよびSSGのNext.jsアプリケーションは、クライアントサイドレンダリング(CSR)のReactアプリケーションよりも一般的にパフォーマンスが優れています。Next.jsでは、サーバーでデータを取得し、ブラウザがレンダリングに必要とするすべてのものを送信することで、APIを用いたデータフェッチの要求が不要になります。これは、読み込み時間の短縮を意味します。

さらに、Next.jsはクライアントサイドルーティングをサポートしています。ユーザーが別のルートに移動しても、都度ブラウザによるサーバーからのデータのフェッチを必要としません。さらに、Next.jsの画像コンポーネントは、画像の自動最適化を可能にします。画像は、ビューポートに入ったときにだけ読み込まれることになります。また、Next.jsでは可能な限り、WebPのような最新のフォーマットで画像が配信されます。

Next.jsは、フォントの最適化、スマートルートプリフェッチ、バンドリングの最適化にも対応しています。これらの最適化は、Reactでは自動で適用されません。

サポート

ReactはNext.jsよりも歴史が長いため、コミュニティの大きさで勝ります。しかし、多くのReact開発者がNext.jsを採用しているため、そのコミュニティは着実に成長しています。問題が発生したときには、ゼロから解決策を考えるよりも、既存の事例を見つけて利用することができます。

また、Next.jsはドキュメントが充実しており、分かりやすいサンプルが揃っていることも特徴です。一方で、Reactのドキュメントは、その人気にもかかわらず、そこまで見やすいものとは言えないかもしれません。

まとめ

Next.jsとReactのどちらを選択するかは、アプリケーションの要件次第です。

Next.jsは、パフォーマンスを向上させる構造とツールで、Reactの機能の強化に成功しています。ルーティング、コード分割、画像最適化などの機能がNext.jsに組み込まれており、開発の際に手動で設定する必要はありません。これらの機能により、Next.jsは使いやすい選択肢であり、すぐにその後のコーディングに着手することができます。

Next.jsは、さまざまなレンダリングオプションを備えているため、サーバーサイドレンダリングアプリケーションや、静的生成とNode.jsサーバーサイドレンダリングを組み合わせたアプリケーションに適しています。また、最適化機能により、Next.jsはECのような高速性が要求されるサイトにも向いています。

Reactは、堅牢なフロントエンドアプリケーションの作成と拡張を支援するJavaScriptライブラリです。また、その構文はわかりやすく、特にJavaScriptのバックグラウンドを持つ開発者にとっては有用です。さらに、アプリケーションで使用するツールやその設定方法を事細かにコントロールすることができます。

アプリケーションの開発を計画中であれば、ReactとNext.jsのいずれを使う場合であっても、KinstaのNode.jsアプリケーションホスティングをご確認ください。

Salman Ravoof

独学のウェブ開発者、ライター、クリエイターでもあり、大の無料オープンソースソフトウェア(FOSS)好き。その他の好きなものは、科学、哲学、写真、芸術、猫、そして食。詳しい仕事情報はウェブサイトおよびXアカウントで公開している。