From 0d72befefadc46419854bdf87d5d267be7a54fb6 Mon Sep 17 00:00:00 2001 From: Elliot Hesp Date: Fri, 20 Dec 2024 16:01:07 +0000 Subject: [PATCH] docs: Update data connect docs --- docs.json | 29 ++++- .../hooks}/useConnectMutation.mdx | 28 +++-- .../hooks}/useConnectQuery.mdx | 4 +- docs/react/data-connect/index.mdx | 67 +++++++++++ docs/react/data-connect/mutations.mdx | 85 ++++++++++++++ docs/react/data-connect/querying.mdx | 80 +++++++++++++ .../data-connect/server-side-rendering.mdx | 106 ++++++++++++++++++ 7 files changed, 383 insertions(+), 16 deletions(-) rename docs/react/{hooks/data-connect => data-connect/hooks}/useConnectMutation.mdx (63%) rename docs/react/{hooks/data-connect => data-connect/hooks}/useConnectQuery.mdx (72%) create mode 100644 docs/react/data-connect/index.mdx create mode 100644 docs/react/data-connect/mutations.mdx create mode 100644 docs/react/data-connect/querying.mdx create mode 100644 docs/react/data-connect/server-side-rendering.mdx diff --git a/docs.json b/docs.json index b2d092f7..0a608937 100644 --- a/docs.json +++ b/docs.json @@ -53,12 +53,33 @@ "group": "Data Connect", "pages": [ { - "href": "/react/hooks/data-connect/useConnectQuery", - "title": "useConnectQuery" + "title": "Getting Started", + "href": "/react/data-connect" }, { - "href": "/react/hooks/data-connect/useConnectMutation", - "title": "useConnectMutation" + "title": "Querying", + "href": "/react/data-connect/querying" + }, + { + "title": "Mutations", + "href": "/react/data-connect/mutations" + }, + { + "title": "Server Side Rendering", + "href": "/react/data-connect/server-side-rendering" + }, + { + "group": "Hooks", + "pages": [ + { + "title": "useConnectQuery", + "href": "/react/data-connect/hooks/useConnectQuery" + }, + { + "title": "useConnectMutation", + "href": "/react/data-connect/hooks/useConnectMutation" + } + ] } ] }, diff --git a/docs/react/hooks/data-connect/useConnectMutation.mdx b/docs/react/data-connect/hooks/useConnectMutation.mdx similarity index 63% rename from docs/react/hooks/data-connect/useConnectMutation.mdx rename to docs/react/data-connect/hooks/useConnectMutation.mdx index bcda15de..8bf07811 100644 --- a/docs/react/hooks/data-connect/useConnectMutation.mdx +++ b/docs/react/data-connect/hooks/useConnectMutation.mdx @@ -3,14 +3,14 @@ title: useConnectMutation --- `useConnectMutation` is a hook designed to simplify handling mutations (creating, updating, deleting) with Firebase Data Connect. -This hook integrates with [Firebase Data Connect](https://firebase.google.com/docs/data-connect), which uses GraphQL to interact with a PostgreSQL database (via Cloud SQL) for secure, scalable data operations. -The hook manages the mutation process and provides an easy-to-use interface to manage loading, success, and error states in your React application. + +See [mutations](/react/data-connect/mutations) for more information. ## Features - Simplifies mutation handling for create, update, and delete operations using Firebase Data Connect. - Provides type-safe handling of mutations based on your Firebase Data Connect schema. -- Automatically manages loading, success, and error states for mutations. +- Automatically manages pending, success, and error states for mutations. - Supports optimistic updates and caching to improve user experience and performance. ## Usage @@ -23,21 +23,29 @@ function Component() { const { mutate, isPending, isSuccess, isError, error } = useConnectMutation(createMovieRef); - const handleSubmit = async (movieData) => { - try { - await mutate(movieData); - } catch (err) { - console.error("Failed to add movie:", err); - } + const handleFormSubmit = (e: React.FormEvent) => { + e.preventDefault(); + const data = new FormData(e.target as HTMLFormElement); + + mutate({ + title: data.get("title") as string, + imageUrl: data.get("imageUrl") as string, + genre: data.get("genre") as string, + }); }; if (isPending) return
Adding movie...
; + if (isError) return
Error: {error.message}
; return (
{isSuccess &&
Movie added successfully!
} -
handleSubmit(e.target)}> + + + + + {/* Form fields for movie data */} + ); +} +``` + +## Invalidating Queries + +The hook provides an additional [mutation option](https://tanstack.com/query/latest/docs/framework/react/reference/useMutation) called `invalidate`. This option accepts a list of query references which will be automatically invalidated when the mutation is successful. + +```tsx +const createMovie = useConnectMutation(createMovieRef, { + invalidate: [getMovieRef], +}); +``` + +### Implicit references + +The above example provides a `getMovieRef` instance to the invalidate array. By default this will invalidate all queries that cached via the `getMovieRef` reference, for example the following query references will be invalidated: + +```tsx +getMovieRef({ id: "1"}); +getMovieRef({ id: "2"}); +``` + +### Explicit references + +You can also provide explicit references to the invalidate array, for example: + +```tsx +const createMovie = useConnectMutation(createMovieRef, { + invalidate: [getMovieRef({ id: "1" })], +}); +``` + +In this case only the query reference `getMovieRef({ id: "1" })` will be invalidated. + +## Overriding the mutation key + +### Metadata + +Along with the data, the hook will also return the `ref`, `source`, and `fetchTime` metadata from the mutation. + +```tsx +const createMovie = useConnectMutation(createMovieRef); + +const data = await createMovie.mutateAsync({ + title: 'John Wick', + genre: "Action", + imageUrl: "https://example.com/image.jpg", +}); + +console.log(data.ref); +console.log(data.source); +console.log(data.fetchTime); +``` \ No newline at end of file diff --git a/docs/react/data-connect/querying.mdx b/docs/react/data-connect/querying.mdx new file mode 100644 index 00000000..d37986e1 --- /dev/null +++ b/docs/react/data-connect/querying.mdx @@ -0,0 +1,80 @@ +--- +title: Querying +description: Learn how to query data from Firebase Data Connect using the Tanstack Query Firebase hooks. +--- + +## Querying Data + +To query data from Firebase Data Connect, you can use the `useConnectQuery` hook. This hook will automatically infer the data type from the connector and the query and automtically create a [query key](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) for the query. + +```tsx +import { useConnectQuery } from "@tanstack-query-firebase/react"; +import { listMoviesRef } from "@dataconnect/default-connector"; + +function Component() { + const { data, isPending, isSuccess, isError, error } = useConnectQuery( + listMoviesRef() + ); +} +``` + +### Query options + +To leverage the full power of Tanstack Query, you can pass in query options to the `useConnectQuery` hook, for example to refetch the query on a interval: + +```tsx +const { data, isPending, isSuccess, isError, error } = useConnectQuery( + listMoviesRef(), + { + refetchInterval: 1000, + } +); +``` + +The hook extends the [`useQuery`](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery) hook, so you can learn more about the available options by reading the [Tanstack Query documentation](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery). + +### Overriding the query key + +To override the query key, you can pass in a custom query key to the `useConnectQuery` hook: + +```tsx +const { data, isPending, isSuccess, isError, error } = useConnectQuery( + getMovieRef({ id: "1" }), + { + queryKey: ["movies", "1"], + } +); +``` + +Note that overriding the query key could mean your query is no longer synchronized with mutation invalidations or server side rendering pre-fetching. + +### Initial data + +If your application has already fetched a data from Data Connect, you can instead pass the `QueryResult` instance to the hook. This will instead set the `initialData` option on the hook: + +```tsx +// Elsewhere in your application +const movies = await executeQuery(listMoviesRef()); + +// ... + +function Component(props: { movies: QueryResult }) { + const { data, isPending, isSuccess, isError, error } = useConnectQuery( + props.movies + ); +} +``` + +The hook will immediately have data available, and immediately refetch the data when the component is mounted. This behavior can be contolled by providing a `staleTime` value to the hook or Query Client. + +### Metadata + +Along with the data, the hook will also return the `ref`, `source`, and `fetchTime` metadata from the query. + +```tsx +const { data } = useConnectQuery(listMoviesRef()); + +console.log(data?.ref); +console.log(data?.source); +console.log(data?.fetchTime); +``` diff --git a/docs/react/data-connect/server-side-rendering.mdx b/docs/react/data-connect/server-side-rendering.mdx new file mode 100644 index 00000000..7ae97dbf --- /dev/null +++ b/docs/react/data-connect/server-side-rendering.mdx @@ -0,0 +1,106 @@ +--- +title: Server Side Rendering +description: Learn how to use Tanstack Query Firebase hooks for server side rendering. +--- + +## Server Side Rendering + +The Data Connect package provides a `DataConnectQueryClient` class that extends the `QueryClient` class. This class provides an additional method called `prefetchDataConnectQuery` that allows you to prefetch data for server side rendering. + +## Server Side Rendering (with Next.js) + +Using [traditional server side rendering](https://tanstack.com/query/latest/docs/framework/react/guides/ssr), the query client instance can be passed to the client "dehydrated", and then rehydrated on the client side. + +The following example demonstrates how to do this with the `DataConnectQueryClient` class and a Next.js application. The data will be immediately available to the client, and the query client will be hydrated on the client side. + +> Ensure you have followed the [initial setup](https://tanstack.com/query/latest/docs/framework/react/guides/ssr#initial-setup) steps first! + +```tsx +import type { InferGetStaticPropsType } from "next"; +import { dehydrate, HydrationBoundary } from "@tanstack/react-query"; +import { listMoviesRef } from "@dataconnect/default-connector"; +import { DataConnectQueryClient } from "@tanstack-query-firebase/react/data-connect"; + +export async function getStaticProps() { + const queryClient = new DataConnectQueryClient(); + + // Prefetch the list of movies + await queryClient.prefetchDataConnectQuery(listMoviesRef()); + + return { + props: { + dehydratedState: dehydrate(queryClient), + }, + }; +} + +export default function MoviesRoute({ + dehydratedState, +}: InferGetStaticPropsType) { + return ( + + + + ); +} + +function Movies() { + const movies = useConnectQuery(listMoviesRef()); + + if (movies.isLoading) { + return
Loading...
; + } + + if (movies.isError) { + return
Error: {movies.error.message}
; + } + + return ( +
+

Movies

+
    + {movies.data!.movies.map((movie) => ( +
  • {movie.title}
  • + ))} +
+
+ ); +} +``` + +### React Server Components (RSC) + +If you are oping into using React Server Components, you can similarly use the `DataConnectQueryClient` class to prefetch data within your server component: + +```tsx +import { Movies } from "@/examples/data-connect"; +import { listMoviesRef } from "@dataconnect/default-connector"; +import { DataConnectQueryClient } from "@tanstack-query-firebase/react"; +import { dehydrate, HydrationBoundary } from "@tanstack/react-query"; + +import "@/firebase"; + +export default async function PostsPage() { + const queryClient = new DataConnectQueryClient(); + + // Prefetch the list of movies + await queryClient.prefetchDataConnectQuery(listMoviesRef()); + + return ( + + + + ); +} + +function Movies() { + const movies = useConnectQuery(listMoviesRef()); + + // ... +} +``` + +### Gotchas + +- If you opt-in to providing a custom `queryKey` to either the prefetched data or the `useConnectQuery` hook, you must ensure that the `queryKey` is the same for both. +- By default, the client will always refetch data in the background. If this behaviour is not desired, you can set the `staleTime` option in your Query Client or hook options.