dotansimha/graphql-code-generator-community

typescript-vue-urql not using useClientHandle -> causing error with suspense

Open

#136 创建于 2021年7月7日

在 GitHub 查看
 (2 评论) (4 反应) (0 负责人)TypeScript (195 fork)github user discovery
help wanted

仓库指标

Star
 (136 star)
PR 合并指标
 (PR 指标待抓取)

描述

Describe the bug In the @graphql-codegen/typescript-vue-urql plugin, the composition functions refer to the global Urql imported as such: import * as Urql from '@urql/vue';. Whilst this can be configured to point to a different instance, there isn't any support for useClientHandle.

Why is this important? When using an async setup function, only one promise can be awaited. Therefore, if I generate two queries and call/await on them sequentially, the second will throw the error: Error: use* functions may only be called during the setup() or other lifecycle hooks..

The problem is explained by the urql team here.

To Reproduce

import { useFlightsFromOriginQuery, useFlightsToDestinationQuery } from '../generated/graphql'

export async function useRoutes() {
  const originFlights = await useFlightsFromOriginQuery()
  const destinationFlights = await useFlightsToDestinationQuery()

return { originFlights, destinationFlights }

The error Error: use* functions may only be called during the setup() or other lifecycle hooks. is thrown when I am calling from my setup function:

<script setup>
import { useRoutes } from '../composables/useRoutes'

const responses = await useRoutes()

</script>

However, this error does not throw if I change the useRoutes() query to only run one of the queries and not the other. As explained by the urql team, this doesn't necessarily mean two queries generated from this library, it means any two promises in the setup function.

This means we need to create the clientHandle in the original setup function and pass it into the use* generated query.

Perhaps the easiest way to fix this is to pass down the Urql as an optional parameter to the auto-generated composition function: https://github.com/dotansimha/graphql-code-generator/blob/988b8b67294e15b7548a554226ee51fce5a4ef4f/packages/plugins/typescript/vue-urql/src/visitor.ts#L73-L74

Which means from my calling code, I can write:

import { useClientHandle } from '@urql/vue'
import { useFlightsFromOriginQuery, useFlightsToDestinationQuery } from '../generated/graphql'

export async function useRoutes() {
  const client = useClientHandle()
  const originFlights = await useFlightsFromOriginQuery({}, client)
  const destinationFlights = await useFlightsToDestinationQuery({}, client)

return { originFlights, destinationFlights }

I looked at this as an alternative: https://github.com/dotansimha/graphql-code-generator/blob/988b8b67294e15b7548a554226ee51fce5a4ef4f/packages/plugins/typescript/vue-urql/src/visitor.ts#L38

But we can't call useClientHandle() until we are actually inside the setup function, meaning the actual composition functions need to change OR we just pass it in from outside.

Perhaps it would be neater if we merged it as an option to the default UseQueryArgs, but I'm open to different options.

Sandbox with types generated: https://codesandbox.io/s/elated-ramanujan-vf6jq?file=/types.ts

贡献者指南