-
-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #342 from psteinroe/feat/ssr
feat/ssr
- Loading branch information
Showing
27 changed files
with
835 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"@supabase-cache-helpers/postgrest-react-query": minor | ||
"@supabase-cache-helpers/postgrest-core": minor | ||
"@supabase-cache-helpers/postgrest-swr": minor | ||
--- | ||
|
||
feat: add prefetch |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"swr": "SWR", | ||
"react-query": "React Query" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { Callout, Tabs, Tab } from "nextra-theme-docs"; | ||
|
||
# Server Side Rendering with React Query | ||
|
||
React Query offers two APIs to supply initial data for a query to the cache before you need it: Declaratively using [`initialData`](https://tanstack.com/query/v4/docs/react/guides/initial-query-data), and imperatively using [`prefetchQuery`](https://tanstack.com/query/v5/docs/react/guides/advanced-ssr). | ||
|
||
Supabase Cache Helpers exports utilities for both. | ||
|
||
## Declaratively providing `initialData` | ||
|
||
Fetch initial data for `useQuery` using `fetchQueryInitialData`. | ||
|
||
```tsx | ||
const buildQuery = (supabase: SupabaseClient) => { | ||
return supabase.from('article').select('id,title'); | ||
}; | ||
|
||
export async function getStaticProps() { | ||
const supabase = createClient( | ||
process.env.NEXT_PUBLIC_SUPABASE_URL, | ||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, | ||
); | ||
const [key, initialData] = await fetchQueryInitialData( | ||
buildQuery(supabase), | ||
); | ||
return { | ||
props: { | ||
initialData | ||
}, | ||
}; | ||
} | ||
|
||
export default function Articles({ initialData }) { | ||
const supabase = useSupabaseClient(); | ||
|
||
const { data } = useQuery(buildQuery(supabase), { initialData }); | ||
... | ||
|
||
} | ||
``` | ||
|
||
## Imperatively prefetch query data | ||
|
||
You can also use leverage `prefetchQuery` to prefetch data for `useQuery` imperatively and pass it to the client using the hydration APIs. | ||
|
||
```tsx | ||
const buildQuery = (supabase: SupabaseClient) => { | ||
return supabase.from('article').select('id,title'); | ||
}; | ||
|
||
export async function getStaticProps() { | ||
const queryClient = new QueryClient() | ||
const supabase = createClient( | ||
process.env.NEXT_PUBLIC_SUPABASE_URL, | ||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, | ||
); | ||
await prefetchQuery(queryClient, buildQuery(supabase)); | ||
return { | ||
props: { | ||
dehydratedState: dehydrate(queryClient), | ||
}, | ||
}; | ||
} | ||
|
||
function Articles() { | ||
const supabase = useSupabaseClient(); | ||
|
||
const { data } = useQuery(buildQuery(supabase)); | ||
... | ||
} | ||
|
||
export default ArticlesRoute({ dehydratedState }) { | ||
return ( | ||
<HydrationBoundary state={dehydratedState}> | ||
<Articles /> | ||
</HydrationBoundary> | ||
) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
import { Callout, Tabs, Tab } from "nextra-theme-docs"; | ||
|
||
# Server Side Rendering with SWR | ||
|
||
SWR allows a user to [pre-render with default data](https://swr.vercel.app/docs/with-nextjs). Specifically, you can either pass `fallbackData` directly to `useSWR`, | ||
|
||
```tsx | ||
const { data } = useSWR("/api/article", fetcher, { fallbackData }); | ||
``` | ||
|
||
or define it globally in `SWRConfig` | ||
|
||
```tsx | ||
<SWRConfig value={{ fallback }}> | ||
<Article /> | ||
</SWRConfig> | ||
``` | ||
|
||
Supabase Cache Helpers exports helper to simplify it for every query type. | ||
|
||
### `useQuery` | ||
|
||
Fetch fallback data for `useQuery` using `fetchQueryFallbackData`. | ||
|
||
```tsx | ||
const buildQuery = (supabase: SupabaseClient) => { | ||
return supabase.from('article').select('id,title'); | ||
}; | ||
|
||
export async function getStaticProps() { | ||
const supabase = createClient( | ||
process.env.NEXT_PUBLIC_SUPABASE_URL, | ||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, | ||
); | ||
const [key, fallbackData] = await fetchQueryFallbackData( | ||
buildQuery(supabase), | ||
); | ||
return { | ||
props: { | ||
fallback: fallbackData, | ||
}, | ||
}; | ||
} | ||
|
||
export default function Articles({ fallback }) { | ||
const supabase = useSupabaseClient(); | ||
|
||
const { data } = useQuery(buildQuery(supabase), { fallbackData: fallback }); | ||
... | ||
|
||
} | ||
``` | ||
|
||
The data can also be passed globally using `key`. | ||
|
||
```tsx | ||
const buildQuery = (supabase: SupabaseClient) => { | ||
return supabase.from('article').select('id,title'); | ||
}; | ||
|
||
export async function getStaticProps() { | ||
const supabase = createClient( | ||
process.env.NEXT_PUBLIC_SUPABASE_URL, | ||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, | ||
); | ||
const [key, fallbackData] = await fetchQueryFallbackData( | ||
buildQuery(supabase), | ||
); | ||
return { | ||
props: { | ||
fallback { | ||
[key]: fallbackData, | ||
}, | ||
}; | ||
} | ||
|
||
export default function App({ fallback }) { | ||
return ( | ||
<SWRConfig value={{ fallback }}> | ||
<Article /> | ||
</SWRConfig> | ||
) | ||
} | ||
``` | ||
### `useOffsetInfiniteQuery` | ||
To fetch fallback data for `useOffsetInfiniteQuery`, use `fetchOffsetPaginationFallbackData`. | ||
```tsx | ||
const buildQuery = (supabase: SupabaseClient) => { | ||
return supabase.from('article').select('id,title'); | ||
}; | ||
|
||
export async function getStaticProps() { | ||
const supabase = createClient( | ||
process.env.NEXT_PUBLIC_SUPABASE_URL, | ||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, | ||
); | ||
const [key, fallbackData] = await fetchOffsetPaginationFallbackData( | ||
buildQuery(supabase), 1 | ||
); | ||
return { | ||
props: { | ||
fallback: fallbackData, | ||
}, | ||
}; | ||
} | ||
|
||
export default function Articles({ fallback }) { | ||
const supabase = useSupabaseClient(); | ||
|
||
const { data } = useOffsetInfiniteQuery(buildQuery(supabase), { | ||
pageSize: 1, | ||
fallbackData, | ||
}); | ||
... | ||
|
||
} | ||
``` | ||
<Callout emoji="🚧"> | ||
Unfortunately, passing it globally to `SWRConfig` does not work. There seems | ||
to be an issue with `fallbackData` in `useSWRInfinite` that I could not figure | ||
out yet. | ||
</Callout> | ||
### `useOffsetInfiniteScrollQuery` | ||
To fetch fallback data for `useOffsetInfiniteScrollQuery`, use `fetchOffsetPaginationHasMoreFallbackData`. | ||
```tsx | ||
const buildQuery = (supabase: SupabaseClient) => { | ||
return supabase.from('article').select('id,title'); | ||
}; | ||
|
||
export async function getStaticProps() { | ||
const supabase = createClient( | ||
process.env.NEXT_PUBLIC_SUPABASE_URL, | ||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, | ||
); | ||
const [key, fallbackData] = await fetchOffsetPaginationHasMoreFallbackData( | ||
buildQuery(supabase), 1 | ||
); | ||
return { | ||
props: { | ||
fallback: fallbackData, | ||
}, | ||
}; | ||
} | ||
|
||
export default function Articles({ fallback }) { | ||
const supabase = useSupabaseClient(); | ||
|
||
const { data } = useOffsetInfiniteScrollQuery(buildQuery(supabase), { | ||
pageSize: 1, | ||
fallbackData, | ||
}); | ||
... | ||
|
||
} | ||
``` | ||
<Callout emoji="🚧"> | ||
Unfortunately, passing it globally to `SWRConfig` does not work. There seems | ||
to be an issue with `fallbackData` in `useSWRInfinite` that I could not figure | ||
out yet. | ||
</Callout> | ||
### `useInfiniteOffsetPaginationQuery` | ||
To fetch fallback data for `useInfiniteOffsetPaginationQuery`, use `fetchOffsetPaginationHasMoreFallbackData`. | ||
```tsx | ||
const buildQuery = (supabase: SupabaseClient) => { | ||
return supabase.from('article').select('id,title'); | ||
}; | ||
|
||
export async function getStaticProps() { | ||
const supabase = createClient( | ||
process.env.NEXT_PUBLIC_SUPABASE_URL, | ||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, | ||
); | ||
const [key, fallbackData] = await fetchOffsetPaginationHasMoreFallbackData( | ||
buildQuery(supabase), 1 | ||
); | ||
return { | ||
props: { | ||
fallback: fallbackData, | ||
}, | ||
}; | ||
} | ||
|
||
export default function Articles({ fallback }) { | ||
const supabase = useSupabaseClient(); | ||
|
||
const { data } = useInfiniteOffsetPaginationQuery(buildQuery(supabase), { | ||
pageSize: 1, | ||
fallbackData, | ||
}); | ||
... | ||
|
||
} | ||
``` | ||
<Callout emoji="🚧"> | ||
Unfortunately, passing it globally to `SWRConfig` does not work. There seems | ||
to be an issue with `fallbackData` in `useSWRInfinite` that I could not figure | ||
out yet. | ||
</Callout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
6c613e2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
supabase-cache-helpers-react-query – ./examples/react-query
supabase-cache-helpers-react-query-git-main-psteinroe.vercel.app
supabase-cache-helpers-react-query-psteinroe.vercel.app
supabase-cache-helpers-react-query.vercel.app
6c613e2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
supabase-cache-helpers-swr-demo – ./examples/swr
supabase-cache-helpers-swr-demo-psteinroe.vercel.app
supabase-cache-helpers-swr.vercel.app
supabase-cache-helpers-swr-demo-git-main-psteinroe.vercel.app
6c613e2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
supabase-cache-helpers – ./docs
supabase-cache-helpers.vercel.app
supabase-cache-helpers-psteinroe.vercel.app
supabase-cache-helpers-git-main-psteinroe.vercel.app