13
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Next.js(App router)でrouter.push()のページ遷移が非常に遅かったのでlazy loadingを取り入れてみた

Last updated at Posted at 2023-12-12

はじめに

社内ツールでNext.js(App router)を使用する中で困ったことと解決策を記載してみます。
Next.jsもApp routerもまだまだ触り始めたばかりですのでもし誤った認識があればご教示いただけます幸いです。

今回困ったこと

あるページ(以下、Page A)からの特定のアクション(たとえばクリックなど)をきっかけにrouter.push()を使用して別のページ(以下、Page B)に遷移する機能を実装しようとしました。

しかし、router.push()による遷移先であるPage Bには非常に時間のかかるfetchを扱うサーバーコンポーネントが存在しており、そのためrouter.push()が発火してからもサーバーサイドでPage Bを読み込んでいる間Page Aに留まり、結果としてPage Bへの遷移までに時間がかかるという問題が発生しました。

Page Bでのfetch処理のパフォーマンスを改善することで根本的な解決を行いましたが、修正の過程で別の解決策も有用でしたので、以下に記載します。

解決策

lazy loadingを使用することで、Page Bに遷移してから重いコンポーネントをloadingする


MDNではlazy loadingは(遅延読み込み)以下のように説明されています。

遅延読み込み (Lazy loading) とは、リソースをノンブロッキング(クリティカルでない)ものとして識別し、必要なときだけこれらを読み込む戦略のことです。クリティカルレンダリングパス (en-US)の長さを短縮する方法であり、ページのロード時間の短縮につながります。

具体的なコード

lazy loadingの書き方は2パターンあるようです。

前提:lazy loadingしないパターン

// Server Component:
import MyServerComponent from '../components/MyServerComponent'
 
export default function ServerComponentExample() {
    return (
        <div>
            <div>lazy loadingしないパターン</div>
            <MyServerComponent />
        </div>
    )
}

これはlazy loadingしていないコードで、MyServerComponentが読み込まれるまでページ全体が読み込まれません。
このMyServerComponentをlazy loadingするように書き換えたいと思います!

パターン1:Dynamic Importsを使用する

import dynamic from 'next/dynamic'
 
// Server Component:
const MyServerComponent = dynamic(() => import('../components/MyServerComponent'))
 
export default function ServerComponentExample() {
    return (
        <div>
            <div>この文字はページ遷移後すぐに表示されますが、Componentは遷移してから読み込みが始まります</div>
            <MyServerComponent />
        </div>
    )
}

こちらは公式にも詳しく記載されている方法です。
上記のような書き方を行うことでMyServerComponentがlazy loadingされます。
サーバーコンポーネントを動的にインポートする場合、サーバーコンポーネント自体ではなく、サーバーコンポーネントの子であるクライアントコンポーネントのみがlazy loadingされるようです。

パターン2:React.lazy()&Suspenseを使用する

import { Suspense, lazy } from 'react'
import { Spinner } from '../components/Spinner'
const MyServerComponent = lazy(() => import('../components/MyServerComponent'))

export const dynamic = 'force-dynamic'

export default function ServerComponentExample() {
    return (
        <>
        	<div>この文字はページ遷移後すぐに表示されますが、Componentは遷移してから読み込みが始まります</div>
            <Suspense fallback={<Spinner />}> 
                <MyServerComponent />
            </Suspense>
        </>
    )
}

そもそもnext/dynamicはReact.lazy() と Suspenseの合わせ技のような書き方で、Next.jsのドキュメントから察するにnext/dynamicを使うのが一般的のようです。

一方で、サンプルコードにも記載したexport const dynamic = 'force-dynamic’(SSG無効)などをはじめとしたexport const dynamic = 'xxx’を使用している部分では、React.lazy()&Suspenseを使用する方が使いやすいな個人的に思いました。
理由はパターン1のnext/dynamicを使うと import dynamic from 'next/dynamic'export const dynamic = 'xxx’とで、変数のdynamicがバッティングしてしまうためです。

まとめ

router.push()によるpage遷移が遅いのはユーザーにとってストレスなので、一解決策としてlazy loadingは有用だなと思いました。

参考になれば幸いです。

参考

13
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?