Skip to content
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

Devtools breaks when using it inside a component and some other errors #74

Open
cannap opened this issue Mar 9, 2023 · 6 comments
Open

Comments

@cannap
Copy link

cannap commented Mar 9, 2023

When using

i have this in a component

const { $client } = useNuxtApp()
const addRecipe = async () => {
 await $client.recipes.create.mutate(recipe.value)

the error is throwing but when i submit something it just works
backend.js:749 TypeError: client[procedureType] is not a function
i also had trycatch and so around same behavior

image

when i remove the code above it works
The Component where i use it https://github.com/cannap/recipes/blob/main/components/common/CommonRecipeWidget.vue

Trpc: https://github.com/cannap/recipes/blob/main/plugins/0.trpc.ts

thanks

@Moonlight63
Copy link

Moonlight63 commented Mar 18, 2023

I am also having the same problem. In fact, even using the example in the playground errors out with TypeError: client[procedureType] is not a function. I am unable to use trpc with this module. Documentation is also very lacking.

Edit: after further testing, I now understand slightly better. I can use trpc to retrieve data, but still any components that use the client just produce errors in the devtools, which effectively means I just can't use it because I really need my devtools to work.

edit edit: This only seems to be a problem when you access the client from top level of component. If you move the logic inside of onMounted like so:

import type { AppRouter } from '@/server/trpc/routers'
const hello = ref<inferRouterOutputs<AppRouter>['hello'] | null>(null)
onMounted(async () => {
  const { $client } = useNuxtApp()
  const { data: todos, pending, error } = await $client.hello.useQuery({ text: 'client' })
  hello.value = todos.value
})

then everything is fine. The only problem now is that it makes the other refs like pending basically useless. If you were to create a new ref outside of onmounted to hold the value of 'pending', you would only be able to set the value of pending after the await statement, at which point you would no longer be pending, unless I am missing something here? Instructions unclear. Please advise.

Edit Edit Edit: OK SO... I have narrowed down the cause/solution, but it's a weird one.
This code results in an error at runtime:

const { $client } = useNuxtApp()
const { data: hello } = await $client.hello.useQuery({ text: "client" })

This code also results in an error:

const client = useNuxtApp().$client
const { data: hello } = await client.hello.useQuery({ text: "client" })

But this code runs perfectly fine with no errors, including in the devtools:

const { data: hello } = await useNuxtApp().$client.hello.useQuery({ text: "client" })

wtf...

Also, using a composable also works perfectly fine...

// composables/useGreeting.ts
export default async function useGreeting(name: string) {
  const { $client } = useNuxtApp()
  return await $client.hello.useQuery({ text: name })
}
// pages/index.ts
const { data:hello, refresh } = await useGreeting("client")

So... Yeah.. That makes no sense to me. If someone wants to explain how perfectly functionally identical code is behaving completely differently... That would improve my sanity.

@cannap
Copy link
Author

cannap commented Mar 28, 2023

@Moonlight63 did this happens inside components or pages? i had no time try if the same happens when we use it in page or in a component

@Moonlight63
Copy link

@cannap This was in a page. I have not tried inside a component, but I would expect the result to be the same since pages are just components anyway. I'll give it a shot.

@nicolassutter
Copy link

@cannap @Moonlight63 👋 Did you ever find out what caused this behavior ?

After investigating a bit it seems it is this line in @trpc/client, createTRPCClientProxy.ts that breaks.

return (client as any)[procedureType](fullPath, ...args)

I built @trpc/client locally and added this snippet bellow right before the return statement, my application's code still worked and my DevTools didn't break 😅

if (!client[procedureType]) {
  console.log(procedureType, client);
  return;
}

return (client as any)[procedureType](fullPath, ...args)

My console.log gave the following result:

image

It definitely seems like procedureType cannot index client in some cases (that I have not determined yet).

Hope this is of use to someone !

@reslear
Copy link

reslear commented Nov 9, 2023

patch base on @nicolassutter solution:

diff --git a/src/createTRPCClientProxy.ts b/src/createTRPCClientProxy.ts
index a4586de4f436e49724fd1b15aefe0a843e7e79cf..23166e54ed661165db34d3231facdbf0fe92e460 100644
--- a/src/createTRPCClientProxy.ts
+++ b/src/createTRPCClientProxy.ts
@@ -122,6 +122,10 @@ export function createTRPCClientProxy<TRouter extends AnyRouter>(
 
       const fullPath = pathCopy.join('.');
 
+      if (!client[procedureType]) {
+        return;
+      }
+      
       return (client as any)[procedureType](fullPath, ...args);
     });
   });

but it seems to have stopped working

@malcock
Copy link

malcock commented Dec 12, 2023

I was able to create a slightly ugly, but easy work around this based on what @Moonlight63 said. You can create a composable that returns the $client object inside a function and it'll work. I wonder whether this method would create a memory leak or something though - maybe could pair it with vueuse sharedComposable?

// ./composables/useTrpc.ts
export default () => {
  const { $apiClient } = useNuxtApp();

  return () => $apiClient;
};

You can use it like so:

// mycomponent.vue
<script setup lang="ts">
import useTrpc from "~/composables/useTrpc";

const tprc = useTprc();

const updateUser = async (id,name) =>{
await tprc().user.updateUser.mutate({
    id,
    name
  });
}
</script>
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants