TECH BLOG

Use Queries - Blitz.js日本語訳ドキュメント

2022-08-12 17:18:06 +09:00

Blitz.jsReactJavaScript

Using Queries

クエリの使用

Reactコンポーネント内での使用

Blitzクエリを使用するには、useQuery フックを次のものと一緒に呼び出します。

  1. 自作したクエリリゾルバ
  2. 自作したクエリ関数の引数
  3. 設定オブジェクト(オプション)

useQuery は、[queryResult, queryExtras] というタプル配列を返します。queryResult には自作したクエリ関数の戻り値が渡されます。

useQueryreact-query をベースに作られているので、自動キャッシュや再検証(revalidation)などの優れた機能を自動的に提供しています。

import { useQuery } from "@blitzjs/rpc"
import getProject from "app/projects/queries/getProject"

function App() {
  const [project] = useQuery(getProject, { where: { id: 1 } })
}

詳細は、 useQuery のドキュメントをご覧ください。

🤔 サーバーコードをコンポーネントにインポートして動くのが不思議かもしれません。サーバー側の関数を直接インポートしている箇所はビルド時にネットワーク呼び出しに置き換えられます。つまり、これらのコードがクライアントコードに含まれることはありません。

デフォルト動作の注意点

初期状態では、useQuery やその他のクエリフックは、合理的だが一歩踏み込んだデフォルト動作が設定されています。これらのデフォルト動作を知らないと習得やデバッグが難しくなったり、予期しない動作をするかもしれません。

  • 現在画面上にレンダリングされているクエリ結果は、解決された直後に「古く」なり、再びレンダリングされたり使用されたりすると、バックグラウンドで自動的にリフェッチされるようになります。これを変更するには、クエリのデフォルトの staleTime0 ミリ秒以外の値に変更します。
  • 使用されなくなった(クエリのすべてのインスタンスがアンマウントされた)クエリの結果は、ガベージコレクションされるまでの間、デフォルトで5分間、再使用される場合に備えてキャッシュされます。これを変更するには、クエリのデフォルトの cacheTime1000 * 60 * 5 ミリ秒以外の値に変更します。
  • 古くなったクエリは、ユーザーがブラウザウィンドウのフォーカスを変えたときや、ブラウザが再接続されたときに、バックグラウンドで自動的に再取得されます。これを無効にするには、クエリの refetchOnWindowFocus オプションと refetchOnReconnect オプションを使用します。
  • 本番環境でネットワークエラーのために失敗したクエリは、静かに自動的に3回再試行され、指数関数的なバックオフ遅延を経て、エラーを捕捉してUIに表示します。これを変更するには、クエリのデフォルトの retry および retryDelay オプションを変更します。
  • デフォルトのクエリ結果は、データが実際に変更されたかどうかを検出するために深層比較 (Deep compare) され、変更されていない場合はデータ参照が変更されないため、useMemo および useCallback に関する値の安定化に役立ちます。ここで使用されているデフォルトの深層比較関数 (config.isDataEqual) は、JSON 互換のプリミティブの比較のみをサポートしています。クエリレスポンスで非JSON互換の値を扱っている場合や、深層比較関数のパフォーマンスに問題がある場合は、この関数を無効にする (config.isDataEqual = () => false) か、ニーズに合わせてカスタマイズする必要があります。

オプション

指定可能な全てのオプションはuseQueryのドキュメントに記載されています。

依存クエリ

依存クエリとは、そのクエリが実行される前に、別のクエリが終了していることに依存するクエリのことです。これを行うには、enabled オプションを使用して、クエリが実行可能なタイミングを指示します。

const [user] = useQuery(getUser, { where: { id: props.query.id } })
const [projects] = useQuery(getProjects, { where: { userId: user.id } }, { enabled: user }))

ページネーション

usePaginatedQueryフックを使用してください。

無限ローディング

useInfiniteQueryフックを使用してください。

プリフェッチ

すべてのクエリは自動的にキャッシュされるので、以下の両方が getProject クエリをキャッシュすることになります。

import { invoke } from "@blitzjs/rpc"

const project = await invoke(getProject, { where: { id: props.id } })
<a onMouseEnter={() => invoke(getProject, { where: { id: props.id } })}>
  View Project
</a>

Blitz はサーバー上で複数のクエリをプリフェッチし、それらのクエリを内部のクエリクライアントにデハイドレート (dehydrate) することもサポートしています。これにより、Blitzはページロード時に即座に利用可能なマークアップをプリレンダリングすることができます。ブラウザでJavaScriptが利用可能になると、Blitzはこれらのクエリをハイドレートし、サーバーでレンダリングされた時点から古くなっている場合は再取得します。

次の例は、Blitz でプリフェッチがどのように機能するかを示しています。

import { gSSP } from "app/blitz-server"
import getProject from "app/projects/queries/getProject"

export const getServerSideProps = gSSP(async ({ ctx }) => {
  // IMPORTANT: the second argument to prefetchBlitzQuery must exactly match the second argument to useQuery down below
  await context.prefetchBlitzQuery(getProject, {
    where: { id: context.params?.projectId },
  })

  return { props: {} }
})

function ProjectPage(props) {
  const [project] = useQuery(getProject, { where: { id: props.id } })
  return <div>{project.name}</div>
}

export default ProjectPage

ユーザー間やリクエスト間でデータが共有されないようにするため、各ページリクエストに対して新しいクエリクライアントが作成されます。データをプリフェッチするには、ctx オブジェクトの prefetchBlitzQuery メソッドを呼び出して、関連する引数とともにリゾルバを渡します。データが取得されると、Blitz はクエリクライアントに対するクエリのデハイドレート (dehydrate) 処理を行います。

クエリのキャンセル

Blitzは、React Queryのデフォルトのクエリキャンセル方法をサポートしています。詳しくはこちらをご覧ください。

また、cancelQueries メソッドを使用して、手動でクエリをキャンセルすることもできます。

import { getQueryClient, getQueryKey, useQuery } from "@blitzjs/rpc"

const [data] = useQuery(getTodos)

return (
  <button
    onClick={(e) => {
      e.preventDefault()
      getQueryClient.cancelQueries(getQueryKey(getTodos))
    }}
  >
    Cancel
  </button>
)

サーバー上での使用

getStaticProps

getStaticProps では、useQuery を使わずに直接クエリ関数を呼び出すことができます。

import getProject from "app/projects/queries/getProject"

export const getStaticProps = async ({ params, ctx }) => {
  const project = await getProject({
    where: { id: context.params?.projectId },
  })
  return { props: { project } }
}

function ProjectPage({ project }) {
  return <div>{project.name}</div>
}

export default ProjectPage

getServerSideProps

getServerSideProps では、invokeWithCtx にクエリ関数を渡すと、クエリ関数の前後に適切なミドルウェアが実行されるようになります。

import { invokeWithCtx } from "@blitzjs/rpc"
import getProject from "app/projects/queries/getProject"
import { gSSP } from "app/blitz-server"

export const getServerSideProps = gSSP(async ({ params, ctx }) => {
  const project = await invokeWithCtx(
    getProject,
    { where: { id: params.projectId } },
    ctx
  )
  return { props: { project } }
})

function ProjectPage({ project }) {
  return <div>{project.name}</div>
}

export default ProjectPage
© 2020 SEMI