Created
December 28, 2022 13:26
-
-
Save fdecampredon/e8e977ea935d8b74ab82afbd3a5b6cf3 to your computer and use it in GitHub Desktop.
Relay and next 13
This file contains hidden or 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 { graphql } from 'graphql'; | |
import schema from './your_schema_path'; | |
import type { VariablesOf, GraphQLTaggedNode } from 'react-relay'; | |
import type { | |
ConcreteRequest, | |
PayloadData, | |
OperationType, | |
} from 'relay-runtime'; | |
export type ServerQuery<TQuery extends OperationType> = { | |
id: string; | |
variables: VariablesOf<TQuery>; | |
payload: PayloadData; | |
}; | |
const preloadServerQuery = async <TQuery extends OperationType>( | |
gqlQuery: GraphQLTaggedNode, | |
variables: VariablesOf<TQuery>, | |
): Promise<ServerQuery<TQuery>> => { | |
if (typeof gqlQuery === 'function') { | |
gqlQuery = gqlQuery(); | |
} | |
if (gqlQuery.kind !== 'Request') { | |
throw new Error( | |
'preloadServerQuery: Expected a graphql`...` tagged query.', | |
); | |
} | |
const request = gqlQuery as ConcreteRequest; | |
const { params } = request; | |
const queryVariables = { ...variables }; | |
const { providedVariables } = params as any; | |
if (providedVariables) { | |
Object.keys(providedVariables).forEach(key => { | |
//@ts-expect-error no types | |
queryVariables[key] = params.providedVariables[key].get(); | |
}); | |
} | |
// fetch instead of graphql if necessary | |
const response = await graphql({ | |
schema, | |
// handle persisted queries is necessary | |
source: params.text as string, | |
variableValues: queryVariables, | |
}); | |
return { | |
id: params.id ?? params.cacheID!, | |
variables, | |
// see https://github.com/apollographql/apollo-server/issues/3149#issuecomment-1117566982 | |
payload: normalizeObject(response.data), | |
}; | |
}; | |
export default preloadServerQuery; | |
const normalizeObject = (obj: any): any => { | |
if (typeof obj !== 'object' || obj == null) { | |
return obj; | |
} | |
if (Array.isArray(obj)) { | |
return obj.map(normalizeObject); | |
} | |
if (!(obj instanceof Object)) { | |
const res = {} as any; | |
const keys = Object.keys(obj); | |
for (const key of keys) { | |
res[key] = normalizeObject(obj[key]); | |
} | |
obj = res; | |
} | |
return obj; | |
}; |
This file contains hidden or 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 { useMemo } from 'react'; | |
import { useRelayEnvironment } from 'react-relay'; | |
// @ts-expect-error no types | |
import useLazyLoadQueryNode from 'react-relay/lib/relay-hooks/useLazyLoadQueryNode'; | |
// @ts-expect-error no types | |
import useMemoOperationDescriptor from 'react-relay/lib/relay-hooks/useMemoOperationDescriptor'; | |
import { __internal } from 'relay-runtime'; | |
import type { ServerQuery } from './preloadServerQuery'; | |
import type { OperationType, GraphQLTaggedNode } from 'relay-runtime'; | |
const { fetchQuery } = __internal; | |
function useServerQuery<TQuery extends OperationType>( | |
gqlQuery: GraphQLTaggedNode, | |
serverQuery: ServerQuery<TQuery>, | |
): TQuery['response'] { | |
const environment = useRelayEnvironment(); | |
const operation = useMemoOperationDescriptor(gqlQuery, serverQuery.variables); | |
if (operation.request.node.params.id !== serverQuery.id) { | |
throw Error( | |
`useServerQuery(): Mismatched version for query '${operation.request.node.params.name}'`, | |
); | |
} | |
// ugly hack to avoid commiting the payload multiple times | |
useMemo(() => { | |
environment.commitPayload(operation, serverQuery.payload); | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, []); | |
return useLazyLoadQueryNode({ | |
componentDisplayName: 'useServerQuery()', | |
fetchKey: null, | |
fetchPolicy: 'store-only', | |
fetchObservable: fetchQuery(environment, operation), | |
query: operation, | |
renderPolicy: null, | |
}); | |
} | |
export default useServerQuery; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment