-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
React Query v3 Support #371
base: master
Are you sure you want to change the base?
Conversation
On reflection I'm not sure if this is really the best solve, as it might break in earlier or future versions of react-query. Because the use of react-query is optional, and a strict version isn't a peer dependancy of My personal preference would be for these "plugins" to be separate dependancies, so each one could have the exact version of it's client as a dependancy. But once you've got a grasp of graphql-zeus's types, it's not that difficult to write your own, and given the QueryKey type shouldn't change much (you'd just have one for Query/QueryRoot or whatever your graphql server defines it as, and one for Mutation/MutationRoot). So, I have been writing my own I'd typically have a file where I use Thunder to create a custom client, then export a query and mutation function that I would use server side, and the hooks for client side. My latest implementation is something like: const client = Thunder(async query => {})
const Scalars = ZeusScalars({
...
})
export const query = () => client('query', { scalars: Scalars })
export const mutation = () => client('mutation', { scalars: Scalars })
export function useTypedQuery<
O extends 'Query',
TData extends ValueTypes[O],
TResult = InputType<GraphQLTypes[O], TData>,
>(
queryKey: QueryKey,
queryGraph: TData | ValueTypes[O],
options?: Omit<UseQueryOptions<TResult>, 'queryKey' | 'queryFn'>,
zeusOptions?: OperationOptions,
) {
return useQuery<TResult>({
queryKey,
queryFn: () =>
client('query', { scalars: Scalars })(
queryGraph,
zeusOptions,
) as Promise<TResult>,
...options,
})
}
export function useTypedMutation<
O extends 'Mutation',
TData extends ValueTypes[O],
TResult = InputType<GraphQLTypes[O], TData>,
TVariables = ExtractVariables<TData>,
>(
mutationKey: MutationKey,
mutation: TData | ValueTypes[O],
options?: Omit<
UseMutationOptions<TResult, unknown, TVariables>,
'mutationKey' | 'mutationFn'
>,
zeusOptions?: OperationOptions,
) {
return useMutation<TResult, unknown, TVariables>({
mutationKey,
mutationFn: variables =>
client('mutation', { scalars: Scalars })(mutation, {
...zeusOptions,
variables: variables as Record<string, undefined>,
}) as Promise<TResult>,
...options,
})
} |
I have to agree that generating these functions are problematic since there are multiple different versions of react query. I have also made my own versions of these functions in my codebase since it makes it easier to supply scalars and the api url. However its quite difficult to do it correctly since there is a lot of types that need to be in the right place. For example in your implementation you did not add the type of An alternative solution might be to just add examples, either in the repo or in the documentation that should be copy-pasted into your code base. The react-query specific code is not dynamic anyway, and it makes it more clear that its your responsibility to keep it up to date if you change versions of react-query or other dependencies. |
@reite Thanks for spotting this, I have to admit I've not actually had a great deal of use for Scalars in the projects I've used this with. But in the one instance the GraphQL server had a DateTime scalar, I was wondering why it was cast as I guess you'd just need to update the TResult type to something like this?
|
Yes that's right. Another issue with your implementation is that it will give a type error if you to use a react-query // My real query function is a bit more complicated than this.
const query = (op) => Chain(url, options)("query", {scalars})(op)
function useTypedQuery<
O extends "query_root",
TData extends ValueTypes[O],
TQResult = InputType<GraphQLTypes[O], TData, typeof scalars>,
TResult = TQResult
>(
queryKey: unknown[],
q: TData | ValueTypes[O],
options?: Omit<
UseQueryOptions<TQResult, unknown, TResult>,
"queryKey" | "queryFn"
>
) {
return useQuery<TQResult, unknown, TResult>(
queryKey,
() => query(q),
options
);
} My main point here is that its pretty difficult to get this right, and I am far from sure I have gotten it right as I dont have deep enough knowledge of zeus and react-query to be sure. I am just improving my implementation as I go along. Personally I find the current react-query generated code to be very lacking for anything except as a starting out point. I am thinking about how we can improve it. The fact that it is a generated makes it more difficult to make improvements. I think a better solution could be to write some documentation or a blog post on how to best use zeus with react query, and expect people to just copy the code instead of generating it. That way we could be explicit about dependencies. What do you @aexol think? Would you prefer to keep the current generated approach or are you open to a different solution? |
Currently the react-query implementation only works with react-query v2. In v3 the generic types passed to the hooks have changed.
They're optional so the two extra
any
types aren't needed, but they override the TResult that is used to describe the data.