Graphql-code-generator: [typescript-react-query] Support React Query 3

Created on 15 Dec 2020  路  7Comments  路  Source: dotansimha/graphql-code-generator

Is your feature request related to a problem? Please describe.


I've updated react-query to version 3 which has breaking changes.

  • The generated file is importing MutationConfig and QueryConfig which no longer exist.
  • The generated hooks should have generic types as we can now transform the fetched data into another type.

Describe the solution you'd like


Support react-query version 3.

  • use UseMutationOptions and UseQueryOptions instead.
  • allow generic types to be able to override the defaults: useQuery<TData = unknown, TError = unknown, TQueryFnData = TData> and useMutation<TData = unknown, TError = unknown, TVariables = void, TContext = unknown>

Additional context

https://react-query.tanstack.com/guides/migrating-to-react-query-3
https://react-query.tanstack.com/guides/migrating-to-react-query-3#query-data-selectors

enhancement need-help plugins waiting-for-release

Most helpful comment

My PR addresses the react-query v3 change for the imports.

  • Also tried to make it configurable. Perhaps naming could be better, though
  • A slight change to the mutations (but perhaps maybe I misunderstood how it was supposed to be used) so that variables are passed to mutate and not at the instantiation.

I haven't taken a look at the generic types yet. I'll try to take a look tomorrow

All 7 comments

My PR addresses the react-query v3 change for the imports.

  • Also tried to make it configurable. Perhaps naming could be better, though
  • A slight change to the mutations (but perhaps maybe I misunderstood how it was supposed to be used) so that variables are passed to mutate and not at the instantiation.

I haven't taken a look at the generic types yet. I'll try to take a look tomorrow

Ok @zbeyens do you mean something like this?
Modified v3 custom hook

export const useListPostsQueryV3 = <TData>(
  variables: ListPostsQueryVariables, 
  options?: UseQueryOptions<ListPostsQuery, unknown, TData>
) =>
  useQuery<ListPostsQuery, unknown, TData>(
    ["ListPosts", variables],
    amplifyFetcher<ListPostsQuery, ListPostsQueryVariables>(
      ListPostsDocument,
      variables
    ),
    options
  );

Example of using the hook

const { data, isLoading, refetch } = useListPostsQueryModified<Post[]>(null, {
    refetchOnWindowFocus: false,
    select: (posts) => posts.listPosts?.items ?? []
  });

This forces the use of a type on the custom useQuery, even when a select is not specified. Unless I'm missing a way to infer the generic type from TData, but I'm not seeing it.

Additionally, should the plugin still support react-query v2 (I made a change to be compatible with both)? Or just force a breaking change?

useQuery

  • useQuery<TData = unknown, TError = unknown, TQueryFnData = TData>

3 generics:

export const useDocumentItemQueryV3 = <
  TData = DocumentItemQuery,
  TError = unknown,
  TQueryFnData = DocumentItemQuery,
>(
  variables: DocumentItemQueryVariables,
  options?: UseQueryOptions<TData, TError, TQueryFnData>
) =>
  useQuery<TData, TError, TQueryFnData>(
    ['DocumentItem', variables],
    fetcher<TQueryFnData | TData, DocumentItemQueryVariables>(
      client,
      DocumentItemDocument,
      variables
    ),
    options
  );
  ```

I think we can omit the third generic as it should always be `TQueryFnData = DocumentItemQuery`, so with 2 generics:

```typescript
export const useDocumentItemQueryV3 = <
  TData = DocumentItemQuery,
  TError = unknown,
>(
  variables: DocumentItemQueryVariables,
  options?: UseQueryOptions<TData, TError, DocumentItemQuery>
) =>
  useQuery<TData, TError, DocumentItemQuery>(
    ['DocumentItem', variables],
    fetcher<DocumentItemQuery, DocumentItemQueryVariables>(
      client,
      DocumentItemDocument,
      variables
    ),
    options
  );

Example of using the hook:

// data type is DocumentItemQuery['document_by_pk']
const { data } = useDocumentItemQueryV3<DocumentItemQuery['document_by_pk']>(
    variables,
    { select: (d) => d.document_by_pk } // new option in v3
  )

This forces the use of a type on the custom useQuery, even when a select is not specified. Unless I'm missing a way to infer the generic type from TData, but I'm not seeing it.

This should not be the case for the above solution.

useMutation

  • useMutation<TData = unknown, TError = unknown, TVariables = void, TContext = unknown>

2 generics, removing variables parameter (see below):

export const useDeleteBlockMutation = <TError = unknown, TContext = unknown>(client: GraphQLClient, options?: UseMutationOptions<DeleteBlockMutation, TError, DeleteBlockMutationVariables, TContext>) => 
  useMutation<DeleteBlockMutation, TError, DeleteBlockMutationVariables, TContext>(
    fetcher<DeleteBlockMutation, DeleteBlockMutationVariables>(client, DeleteBlockDocument),
    options
  );

Mutation variables

When doing a mutation, you currently have to pass the variables when declaring the hook:

// currently
const { mutate } = useDeleteBlockMutation({ id: 1 }, options);

// should be:
const { mutate } = useDeleteBlockMutation(options);
mutate({ id: 1 });

But it's not the official way react-query is passing variables. It's passed in the mutate function for more control (e.g. called in a callback), which is not supported with the current fetcher.

Can you please use this fetcher for mutations (not compatible with queries):

function mutationFetcher<TData, TVariables>(client: GraphQLClient, query: string) {
  return async (variables?: TVariables): Promise<TData> => client.request<TData, TVariables>(query, variables);
}

React-query v2

I would say breaking change. The current version is supporting v2 and does not need to be maintained, so people using react-query 2 can just keep the current version until they upgrade to v3.

@zbeyens Thanks! My generic knowledge is a little lacking. I swear I tried the export const useDocumentItemQueryV3 = <TData = DocumentItemQuery, TError = unknown,>(... example last night and it wasn't working. Fresh day though and it's good to go.

I'll go ahead and rewrite it to drop v2 support. It'll definitely be easier than supporting both.

As for the mutation this appears to work with the current fetch implementations: dropping the variables and calling the function

export const useSubmitRepositoryMutation = (
  dataSource: { endpoint: string; fetchParams?: RequestInit },
  options?: UseMutationOptions<SubmitRepositoryMutation, unknown, SubmitRepositoryMutationVariables>
) =>
  useMutation<SubmitRepositoryMutation, unknown, SubmitRepositoryMutationVariables>(
    (variables?: SubmitRepositoryMutationVariables) =>
      fetcher<SubmitRepositoryMutation, SubmitRepositoryMutationVariables>(
        dataSource.endpoint,
        dataSource.fetchParams || {},
        SubmitRepositoryDocument,
        variables
      )(),
    options
  );

PR has been updated. Let me know what you all think

Perfect! Added a small review

Available in @graphql-codegen/[email protected]. Thank you all!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zenVentzi picture zenVentzi  路  3Comments

leonardfactory picture leonardfactory  路  3Comments

fvisticot picture fvisticot  路  3Comments

dotansimha picture dotansimha  路  3Comments

quolpr picture quolpr  路  3Comments