Skip to content

Commit

Permalink
Merge pull request #342 from psteinroe/feat/ssr
Browse files Browse the repository at this point in the history
feat/ssr
  • Loading branch information
psteinroe authored Dec 8, 2023
2 parents 5a56012 + dbd0fd1 commit 6c613e2
Show file tree
Hide file tree
Showing 27 changed files with 835 additions and 96 deletions.
7 changes: 7 additions & 0 deletions .changeset/fresh-spoons-dream.md
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
3 changes: 2 additions & 1 deletion docs/pages/postgrest/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"queries": "Queries",
"mutations": "Mutations",
"subscriptions": "Subscriptions",
"custom-cache-updates": "Custom Cache Updates"
"custom-cache-updates": "Custom Cache Updates",
"ssr": "Server Side Rendering"
}
4 changes: 4 additions & 0 deletions docs/pages/postgrest/ssr/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"swr": "SWR",
"react-query": "React Query"
}
79 changes: 79 additions & 0 deletions docs/pages/postgrest/ssr/react-query.mdx
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>
)
}
```
210 changes: 210 additions & 0 deletions docs/pages/postgrest/ssr/swr.mdx
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>
2 changes: 1 addition & 1 deletion packages/postgrest-core/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import * as Import from '../src';

describe('index exports', () => {
it('should export', () => {
expect(Object.keys(Import)).toHaveLength(36);
expect(Object.keys(Import)).toHaveLength(38);
});
});
Loading

3 comments on commit 6c613e2

@vercel
Copy link

@vercel vercel bot commented on 6c613e2 Dec 8, 2023

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

@vercel
Copy link

@vercel vercel bot commented on 6c613e2 Dec 8, 2023

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

@vercel
Copy link

@vercel vercel bot commented on 6c613e2 Dec 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.