Last active
March 23, 2023 21:04
-
-
Save litewarp/cc64c7624cad5702923aef62fcb2ff31 to your computer and use it in GitHub Desktop.
Relay Nextjs13
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
'use client' | |
import {graphql} from 'react-relay' | |
import graphqlQuery, { | |
AllSecuritiesPageQuery | |
} from '~/__generated__/AllSecuritiesPageQuery.graphql' | |
import {createRelayHydrator} from '~/lib/relay/create-relay-hydrator' | |
export const {useHydratedPreloadedQuery, Hydrator} = | |
createRelayHydrator<AllSecuritiesPageQuery>(graphqlQuery) | |
const query = graphql` | |
query AllSecuritiesPageQuery( | |
$first: Int = 20 | |
$after: Cursor | |
$filter: SecurityFilter | |
$orderBy: [SecuritiesOrderBy!] | |
) { | |
...SecuritiesTable_securitiesConnection | |
} | |
` | |
export function AllSecuritiesPage() { | |
const data = useHydratedPreloadedQuery(query) | |
return ( | |
<></> | |
) | |
} |
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
import {createContext, ReactNode, Suspense, useContext, useMemo} from 'react' | |
import { | |
GraphQLTaggedNode, | |
PreloadedQuery, | |
usePreloadedQuery, | |
useRelayEnvironment | |
} from 'react-relay' | |
import {RelayNetworkLayer} from 'react-relay-network-modern' | |
import { | |
ConcreteRequest, | |
GraphQLResponse, | |
OperationType, | |
RequestParameters | |
} from 'relay-runtime' | |
import {CacheOption, PreloadedQueryResponse} from '~/lib/relay/types' | |
export type RelayHydratorOptions = { | |
cache?: CacheOption | |
} | |
const endpoint = process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT as string | |
export const getFetchKey = (params: RequestParameters): string => { | |
return params.text ? params.name : params.id ?? '' | |
} | |
export function createRelayHydrator<TOperation extends OperationType>( | |
query: ConcreteRequest, | |
options?: RelayHydratorOptions | |
) { | |
if (!query) throw new Error(`Graphql Request required!`) | |
if (!endpoint) | |
throw new Error(`Must set NEXT_PUBLIC_GRAPHQL_ENDPOINT as an .env variable`) | |
const opts = options ?? ({} as RelayHydratorOptions) | |
const Context = createContext<{query: PreloadedQuery<TOperation>}>( | |
{} as {query: PreloadedQuery<TOperation>} | |
) | |
function PreloadedQueryProvider(props: { | |
children: ReactNode | |
query: PreloadedQueryResponse<TOperation> | |
}) { | |
const environment = useRelayEnvironment() | |
const query: PreloadedQuery<TOperation> = { | |
environment: environment, | |
fetchKey: getFetchKey(props.query.params), | |
fetchPolicy: 'store-or-network', | |
isDisposed: false, | |
name: props.query.params.name, | |
kind: 'PreloadedQuery', | |
variables: props.query.variables, | |
dispose: () => { | |
return // no-op | |
} | |
} | |
return <Context.Provider value={{query}}>{props.children}</Context.Provider> | |
} | |
function Hydrator(props: { | |
query: PreloadedQueryResponse<TOperation> | |
children: ReactNode | |
}) { | |
const {query, children} = props | |
const environment = useRelayEnvironment() | |
const network = environment.getNetwork() as RelayNetworkLayer | |
useMemo(() => { | |
const cache = network.responseCache | |
const key = getFetchKey(query.params) | |
cache.set(key, query.variables, query.response as GraphQLResponse) | |
}, [network.responseCache, query]) | |
return ( | |
<PreloadedQueryProvider query={query}> | |
<Suspense fallback={<>Loading ...</>}>{children}</Suspense> | |
</PreloadedQueryProvider> | |
) | |
} | |
function useHydratedPreloadedQuery(query: GraphQLTaggedNode) { | |
const context = useContext(Context) | |
return usePreloadedQuery(query, context.query) | |
} | |
return { | |
useHydratedPreloadedQuery, | |
Hydrator | |
} | |
} |
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
import {ServerGetToken} from '../types' | |
import {OperationType, RequestParameters} from 'relay-runtime' | |
import {z} from 'zod' | |
import {CacheOption, PreloadedQueryResponse} from '~/lib/relay/types' | |
const endpoint = process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT as string | |
// validate the new nextjs cache options for fetch requests | |
// see https://beta.nextjs.org/docs/api-reference/fetch#optionscache | |
const cacheSchema = z.union([ | |
z.object({ | |
next: z.object({ | |
revalidate: z.number() | |
}) | |
}), | |
z.object({ | |
cache: z.enum(['no-store', 'force-cache']) | |
}) | |
]) | |
export const getCacheOption = (option: unknown): CacheOption => { | |
const valid = cacheSchema.safeParse(option) | |
// default it to no-store for now | |
return valid.success ? valid.data : {cache: 'no-store'} | |
} | |
export async function getPreloadedQuery<TQuery extends OperationType>(args: { | |
params: RequestParameters | |
variables: TQuery['variables'] | |
getToken: ServerGetToken | |
cache?: CacheOption | |
}): Promise<PreloadedQueryResponse<TQuery>> { | |
const {params, variables, getToken, cache} = args | |
const token = await getToken() | |
const res = await fetch(endpoint, { | |
method: 'POST', | |
headers: { | |
Authorization: `Bearer ${token ?? ''}`, | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify({ | |
id: params.id, | |
query: params.text, | |
variables | |
}), | |
...getCacheOption(cache) | |
}) | |
if (!res.ok) { | |
throw new Error( | |
`Error preloading query. Server responded with ${res.status}: ${res.statusText}` | |
) | |
} | |
return { | |
params, | |
variables, | |
response: await res.json() | |
} | |
} |
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
import {auth} from '../getToken' | |
import graphqlQuery, { | |
AllSecuritiesPageQuery | |
} from '~/__generated__/AllSecuritiesPageQuery.graphql' | |
import {AllSecuritiesPage, Hydrator} from '~/app/admin/securities/AllSecuritiesPage' | |
import {getPreloadedQuery} from '~/lib/relay/get-preloaded-query' | |
export default async function AllSecuritiesRootPage() { | |
const {getToken} = auth() | |
const query = await getPreloadedQuery<AllSecuritiesPageQuery>({ | |
params: graphqlQuery.params, | |
variables: { | |
first: 20 | |
}, | |
getToken | |
}) | |
return ( | |
<Hydrator query={query}> | |
<AllSecuritiesPage /> | |
</Hydrator> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment