Queries
The cache helpers query hooks wrap the data fetching hooks of the cache libraries and pass both the cache key and the fetcher function from on the PostgREST query. This is enabled primarily by a parser that turns any Supabase PostgREST query into a definite cache key. For example,
client
.from("contact")
.select("id,username,ticket_number", { count: "exact" })
.eq("username", "psteinroe");
is parsed into
postgrest$null$public$contact$select=id%2Cusername%2Cticket_number&username=eq.psteinroe$null$count=exact$head=false$
Although you can use wildcards (*
) in your query, their usage is only
recommended for head: true
and count: true
queries. For any other query,
you should be explicit about the columns you want to select. Only then is
cache helpers able to do granular cache updates without refetching.
useQuery
Wrapper around the default data fetching hook that returns the query including the count without any modification of the data. The config parameter of the respective library can be passed as the second argument.
import { useQuery } from "@supabase-cache-helpers/postgrest-swr";
const client = createClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
);
function Page() {
const { data, count } = useQuery(
client
.from("contact")
.select("id,username,ticket_number", { count: "exact" })
.eq("username", "psteinroe"),
{
revalidateOnFocus: false,
revalidateOnReconnect: false,
}
);
return <div>...</div>;
}
useInfiniteOffsetPaginationQuery
Wrapper around the infinite hooks that transforms the data into pages and returns helper functions to paginate through them. The range
filter is automatically applied based on the pageSize
parameter. The respective configuration parameter can be passed as second argument.
nextPage()
and previousPage()
are undefined
if there is no next or previous page respectively. setPage
allows you to jump to a page.
The hook does not use a count query and therefore does not know how many pages there are in total. Instead, it queries one item more than the pageSize
to know whether there is another page after the current one.
import { useInfiniteOffsetPaginationQuery } from '@supabase-cache-helpers/postgrest-swr';
import { createClient } from '@supabase/supabase-js';
import { Database } from './types';
const client = createClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
);
function Page() {
const {
currentPage,
nextPage,
previousPage,
setPage,
pages,
pageIndex,
isValidating,
error,
} = useInfiniteOffsetPaginationQuery(
client
.from('contact')
.select('id,username')
.order('username', { ascending: true }),
{ pageSize: 1, revalidateOnReconnect: true }
);
return <div>...</div>;
}
useOffsetInfiniteScrollQuery
Wrapper around the infinite hooks that transforms the data into a flat list and returns a loadMore
function. The range
filter is automatically applied based on the pageSize
parameter. The SWRConfigurationInfinite
can be passed as second argument.
loadMore()
is undefined
if there is no more data to load.
The hook does not use a count query and therefore does not know how many items there are in total. Instead, it queries one item more than the pageSize
to know whether there is more data to load.
import { useOffsetInfiniteScrollQuery } from '@supabase-cache-helpers/postgrest-swr';
import { createClient } from '@supabase/supabase-js';
import { Database } from './types';
const client = createClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
);
function Page() {
const { data, loadMore, isValidating, error } = useOffsetInfiniteScrollQuery(
client
.from('contact')
.select('id,username')
.order('username', { ascending: true }),
{ pageSize: 1 }
);
return <div>...</div>;
}
useCursorInfiniteScrollQuery
After using this hook in production, a few subtile issues were discovered. Please use it with caution. While improving the stability, I might introduce breaking changes.
Similar to useOffsetInfiniteScrollQuery
, but instead of using the offset
filter to paginate, it uses a cursor. You can find a longer rationale on why this is more performant than offset-based pagination here.
For the cursor pagination to work, the query has to have:
- an
order
clause that defines the column and direction in which to paginate - a
limit
clause that defines page size.
loadMore()
is undefined
if there is no more data to load.
The hook does not use a count query and therefore does not know how many items there are in total. You can pass until
, to define until what value data should be loaded. If until
is not defined, loadMore
will always be truthy if the last page had a number of elements equal to the page size.
import { useCursorInfiniteScrollQuery } from '@supabase-cache-helpers/postgrest-swr';
import { createClient } from '@supabase/supabase-js';
import { Database } from './types';
const client = createClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
);
function Page() {
const { data, loadMore, isValidating, error } =
useCursorInfiniteScrollQuery(
client
.from('contact')
.select('id,username')
.ilike('username', `${testRunPrefix}%`)
.order('username', { ascending: true })
.limit(1),
{ path: 'username' },
{ revalidateOnFocus: false }
);
return <div>...</div>;
}
useOffsetInfiniteQuery
Wrapper around the infinite hook that returns the query without any modification of the data.
import { useOffsetInfiniteQuery } from '@supabase-cache-helpers/postgrest-swr';
import { createClient } from '@supabase/supabase-js';
import { Database } from './types';
const client = createClient<Database>(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
);
function Page() {
const { data, size, setSize, isValidating, error, mutate } = useOffsetInfiniteQuery(
client
.from('contact')
.select('id,username')
.order('username', { ascending: true }),
{ pageSize: 1 }
);
return <div>...</div>;
}