Next.js: データ取得を減らし、ページ間でデータを共有する 質問する

Next.js: データ取得を減らし、ページ間でデータを共有する 質問する

私はNext.jsアプリでよりよいデータ取得のためのソリューションを探しています。この質問では、単に1つの解決策として、長所と短所を検討できるように複数のオプションを探しています。

私が抱えている問題

現在、いくつかのページがあり、それらには静的コンテンツを表示するコンポーネントと、APIから取得される動的コンテンツが含まれています。各ページは独自のページデータだけでなくフッターデータも取得するためにfetch()内部で実行します。getInitialProps()すべてのページで同じです

もちろんこれは機能しますが、重複したデータ取得が多数発生します。フッター データは常にすべてのページに表示され、常に同じになります。また、API で変更されることはほとんどないため、データを再検証する必要はありません。

私が探している答え

私は、この 1 つの問題を解決しようとしているのではなく、将来のプロジェクトのために新しい方法を学ぶための概要も探しています。私は「明白な」コードを書くのが好きなので、オブジェクトへの書き込みwindowなど、あまりハッキーなソリューションは求めていません。依存関係の少ないシンプルなソリューションが好まれます。目標は高速なサイトです。ネットワーク使用量や API 呼び出しを減らすことはそれほど重要ではありません。

これまで考えてきたこと

これは私が考え出した可能な解決策であり、単純/明白なものからより複雑なものまで分類されています。

  1. フッターコンポーネント内でフェッチを実行する(クライアント側)
  2. すべての /pages で getInitialProps (サーバー側とクライアント側) のフェッチを実行します。
  3. _app.js で HOC を使用してフェッチし、それにフックしてgetInitialProps()props に追加すると、すべてのページでデータが利用できるようになります。
  4. zeit/swrとデータプリフェッチを使用してデータをキャッシュする
  5. reduxを使用してグローバル状態を保存する

これらはすべて「機能します」が、そのほとんどはデータを不必要に再取得したり、少し複雑になったりします。私が考える長所と短所は次のとおりです (数字は上記と同じです)。

  1. �� シンプルです。フェッチ コードは 1 か所だけ、つまり、使用される場所に配置されます。�� データはページが読み込まれた後にフェッチされるため、コンテンツが「ジャンプ」して表示されます。データは常に再取得されます。
  2. �� 簡単です! データはサーバー上で取得されるため、ページがレンダリングされる前にコンテンツが利用可能になります。 �� データはページごとに再取得されます。各ページで同じフッター データを取得することを忘れないようにする必要がありますgetInitialProps()
  3. �� 1 か所でフェッチして、それをすべてのページのプロパティに追加できるので、フッター データはすべてのページのプロパティで自動的に利用できるようになります。 �� Next.js/React の仕組みをもう少し理解する必要があるため、何が起こっているのかを簡単に理解するには少し複雑すぎるかもしれません。 それでもすべてのページのデータを再取得します。 今度は、2 つのfetch()呼び出しを続けて実行します (最初に _app.js でフッター コンテンツを読み込み、次に各ページでカスタム コンテンツを取得します)。そのため、さらに遅くなります。
  4. �� かなりシンプルです。プリフェッチを使用すると、JS がロードされる前でもデータをキャッシュにロードできます。最初のページがロードされた後、高速なデータ フェッチが行われます。フッター コンポーネントにフェッチ コードを直接含めることができます。�� rel="preload"プリフェッチ手法は、すべてのタイプのフェッチで機能するわけではありません (たとえば、groq を使用する Sanity のクライアント)。最初のページ ロード後にデータがロードされる「ジャンプする」コンテンツを回避するには、 を提供する必要がありますuseSWR()initialDataそれでも でデータを取得する必要がありますgetInitialProps()が、サーバー側でこれを行うだけで十分です。新しい を使用できますgetServerSideProps()
  5. �� データを一度ロードすれば、アプリケーション全体で利用できるようになります。高速で、再フェッチが少なくなります。 �� 外部依存関係が追加されます。共有データ オブジェクトを 1 つロードするだけでも redux を学習する必要があるため、より複雑になります。

現在のソリューションは、箇条書き 2 に記載されているソリューションを使用しています。

const HomePage = (props) => {
  return (
    <Layout data={props.footer}>
       <Home data={props.page} />
    </Layout>
  )
}

// Not actual query, just sample
const query = `{
  "page": *[_type == "page"][0], 
  "footer": *[_type == "footer"][0]
}`

HomePage.getInitialProps = async () => {
  const data = await client.fetch(query)

  return {
    page: data.page
    footer: data.footer
  }
}

export default HomePage

これについてもう少し詳しく知りたいです。何か明らかなことを見逃しているのでしょうか?

ベストアンサー1

そうです!私は何か他のものを探しているときにこのスレッドを見つけました。しかし、私は同様の問題に取り組まなければならなかったので、いくつかの指示を与えることができますし、わかりやすく説明できるように最善を尽くします。

そのため、アプリ全体(ページ/コンポーネント)で共有したいデータがいくつかあります。

  1. Next.js は App コンポーネントを使用してページを初期化します。これをオーバーライドしてページの初期化を制御できます。これを実現するには、ディレクトリ_app.jsのルートにファイルを作成するだけですpages。詳細については、次のリンクを参照してください。https://nextjs.org/docs/advanced-features/カスタムアプリ
  2. ページで を使用して API からデータを取得するのと同じようにgetInitialProps、 でも同じメソッドを使用できます_app.js。そのため、アプリ全体で共有する必要があるデータを取得し、API 呼び出しを削減できます。

さて、アプリ間でデータを共有するには2つの方法が考えられます

  1. createContextフックの使用。

1.1. createContext フックを使用して DataContext を作成し、<Component {...pageProps} />でラップします<DataContext.Provider>。より良いヒントとなるコード スニペットを次に示します。

<DataContext.Provider value={{ userData, footerData, etc... }}>
  <Component {...pageProps} />
</DataContext.Provider>

1.2. これで、他のページ/コンポーネントでは、次のように DataContext にアクセスできるようになります。

const { footerData } = useContext(DataContext); 

そしてフロントエンドで操作できるようになります

  1. props使用して移入するgetInitialProps

2.1. はgetInitialProps、非同期的にデータを取得し、 に入力するために使用されますprops。 の場合も同様です_app.js

コードは_app.js次のようになります:

function MyApp({ Component, pageProps, footerData }) {
  //do other stuffs
  return (
   <Component {...pageProps} footerData={footerData} />
  ;
}

MyApp.getInitialProps = async ({ Component, ctx }) => {
  const footerRes = await fetch('http://API_URL');
  const footerData = await footerRes.json(); 
  let pageProps = {};
  if (Component.getInitialProps) {
    pageProps = await Component.getInitialProps(ctx);
  }
  return { pageProps, footerData };
};

2.2. これで、ページ内 (コンポーネント内ではありません) で、共有したプロパティを含むプロパティにアクセスし_app.js、操作を開始できます。

ヒントや方向性をお伝えできれば幸いです。探索を楽しんでください。

おすすめ記事