T
tRPC
[How To] Properly use trpc UseQuery based on currently selected item
[How To] Properly use trpc UseQuery based on currently selected item
I have a component with a video element and a flatlist. I want to utilize a trpc query to get the videoUri based on the currently selected item.
Here is my working component:
I can use this component in a screen and pass in a {data} prop to override the items and the videos it loads.
I can use a basic trpc query to fetch all posts from my 'wp_posts' table and load them into my component. The query looks like:
Now in my actual database the videoUri lives in another table 'wp_postmeta' and not in the same table that would have the "post_title". I understand I could modify the 'all' trpc query to add the videoUri from the 'postmeta' table into the one query. But this would add unnecessary time to loading the original flatlist which only needs the basic information like post_title.
I assume it is better to call a second query inside the Component that fetches the videoUri based on the currently selected item (currentItem.ID) via a second query function like so:
How would I properly call this second query that only fires once currentItem has a value? I tried placing it insdie a useEffect hook with a condition of [currentItem] but got an error. This is what i tried:
Some research tells me that useQuery is a hook and cannot be called inside useEffect. (https://stackoverflow.com/questions/70300864/how-to-use-usequery-with-useeffect)
i am also trying to use something like:
but have not been able to get it to work
import React, { useState, useRef, FC } from "react";
import { StyleSheet } from "react-native";
import { Text } from "../../../design/typography";
import { View } from "../../../design/view";
import { TouchableOpacity } from "../../button";
import { FlashList } from "@shopify/flash-list";
import { Video, ResizeMode } from "expo-av";
interface CourseComponentProps {
data?: DataItem[];
}
type DataItem = {
ID: bigint;
post_title: string;
videoUri?: string;
};
type ItemProps = {
item: DataItem;
onPress: () => void;
};
const Item = ({ item, onPress }: ItemProps) => (
<TouchableOpacity onPress={onPress}>
<Text>{item.post_title}</Text>
</TouchableOpacity>
);
export const CourseComponent: FC<CourseComponentProps> = ({ data }) => {
const video = React.useRef(null);
const [currentItem, setCurrentItem] = React.useState<DataItem>();
const renderItem = ({ item }: { item: DataItem }) => {
return <Item item={item} onPress={() => setCurrentItem(item)} />;
};
return (
<View className="h-screen">
<Video
ref={video}
style={styles.video}
source={{
uri: currentItem?.videoUri || "",
}}
useNativeControls
resizeMode={ResizeMode.CONTAIN}
isLooping
/>
<Text>{currentItem?.post_title}</Text>
<FlashList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.ID.toString()}
/>
</View>
);
};
CourseComponent.defaultProps = {
data: [
{
ID: BigInt(1),
post_title: "Default Post Title 1",
videoUri: "https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4",
},
...
],
};
import React, { useState, useRef, FC } from "react";
import { StyleSheet } from "react-native";
import { Text } from "../../../design/typography";
import { View } from "../../../design/view";
import { TouchableOpacity } from "../../button";
import { FlashList } from "@shopify/flash-list";
import { Video, ResizeMode } from "expo-av";
interface CourseComponentProps {
data?: DataItem[];
}
type DataItem = {
ID: bigint;
post_title: string;
videoUri?: string;
};
type ItemProps = {
item: DataItem;
onPress: () => void;
};
const Item = ({ item, onPress }: ItemProps) => (
<TouchableOpacity onPress={onPress}>
<Text>{item.post_title}</Text>
</TouchableOpacity>
);
export const CourseComponent: FC<CourseComponentProps> = ({ data }) => {
const video = React.useRef(null);
const [currentItem, setCurrentItem] = React.useState<DataItem>();
const renderItem = ({ item }: { item: DataItem }) => {
return <Item item={item} onPress={() => setCurrentItem(item)} />;
};
return (
<View className="h-screen">
<Video
ref={video}
style={styles.video}
source={{
uri: currentItem?.videoUri || "",
}}
useNativeControls
resizeMode={ResizeMode.CONTAIN}
isLooping
/>
<Text>{currentItem?.post_title}</Text>
<FlashList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.ID.toString()}
/>
</View>
);
};
CourseComponent.defaultProps = {
data: [
{
ID: BigInt(1),
post_title: "Default Post Title 1",
videoUri: "https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4",
},
...
],
};
export const lessonRouter = router({
all: publicProcedure.query(({ ctx }) => {
return ctx.prisma.wp_posts.findMany({
where: {
post_type: "sfwd-lessons",
},
});
}),
});
export const lessonRouter = router({
all: publicProcedure.query(({ ctx }) => {
return ctx.prisma.wp_posts.findMany({
where: {
post_type: "sfwd-lessons",
},
});
}),
});
export const lessonRouter = router({
all: publicProcedure.query(({ ctx }) => {
return ctx.prisma.wp_posts.findMany({
where: {
post_type: "sfwd-lessons",
},
});
}),
videoUri: publicProcedure.input(z.bigint()).query(({ ctx, input }) => {
return ctx.prisma.wp_postmeta.findFirst({
where: {
post_id: input, // Change the post_id value here
meta_key: "app_video_uri", // Replace "video_uri" with the actual meta_key for the meta_value you want to retrieve
},
});
}),
});
export const lessonRouter = router({
all: publicProcedure.query(({ ctx }) => {
return ctx.prisma.wp_posts.findMany({
where: {
post_type: "sfwd-lessons",
},
});
}),
videoUri: publicProcedure.input(z.bigint()).query(({ ctx, input }) => {
return ctx.prisma.wp_postmeta.findFirst({
where: {
post_id: input, // Change the post_id value here
meta_key: "app_video_uri", // Replace "video_uri" with the actual meta_key for the meta_value you want to retrieve
},
});
}),
});
React.useEffect(() => {
const fetchVideoUri = async () => {
if (currentItem?.ID) {
try {
const { data } = await trpc.lesson.videoUri.useQuery(currentItem.ID);
setVideoUri(data?.meta_value ?? undefined);
} catch (error) {
// Handle error
}
}
};
fetchVideoUri();
}, [currentItem]);
React.useEffect(() => {
const fetchVideoUri = async () => {
if (currentItem?.ID) {
try {
const { data } = await trpc.lesson.videoUri.useQuery(currentItem.ID);
setVideoUri(data?.meta_value ?? undefined);
} catch (error) {
// Handle error
}
}
};
fetchVideoUri();
}, [currentItem]);
const { data, error } = trpc.lesson.videoUri.useQuery(currentItem?.id, {
enabled: currentItem?.id !== undefined,
});
const { data, error } = trpc.lesson.videoUri.useQuery(currentItem?.id, {
enabled: currentItem?.id !== undefined,
});
Solution:...Jump to solution
const query = trpc.lesson.videoUri.useQuery(currentItem?.id as string, {
enabled: !!currentItem?.id,
});
const query = trpc.lesson.videoUri.useQuery(currentItem?.id as string, {
enabled: !!currentItem?.id,
});
This is the way to go
Solution
const query = trpc.lesson.videoUri.useQuery(currentItem?.id as string, {
enabled: !!currentItem?.id,
});
const query = trpc.lesson.videoUri.useQuery(currentItem?.id as string, {
enabled: !!currentItem?.id,
});
thank you!
I currently have:
and am getting error:
const { data: videoData, error } = trpc.lesson.videoUri.useQuery(
currentItem?.ID,
{
enabled: !!currentItem,
},
);
const { data: videoData, error } = trpc.lesson.videoUri.useQuery(
currentItem?.ID,
{
enabled: !!currentItem,
},
);
TypeError: Do not know how to serialize a BigInt
TypeError: Do not know how to serialize a BigInt
Add superjson
https://trpc.io/docs/server/data-transformers
it seems i already have that done?
https://github.com/launchthatbrand/t3-turbo-and-clerk/blob/lms/packages/api/src/trpc.ts
import { initTRPC, TRPCError } from "@trpc/server";
import { type Context } from "./context";
import superjson from "superjson";
const t = initTRPC.context<Context>().create({
transformer: superjson,
errorFormatter({ shape }) {
return shape;
},
});
const isAuthed = t.middleware(({ next, ctx }) => {
if (!ctx.auth.userId) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Not authenticated" });
}
return next({
ctx: {
auth: ctx.auth,
},
});
});
export const router = t.router;
export const publicProcedure = t.procedure;
export const protectedProcedure = t.procedure.use(isAuthed);
import { initTRPC, TRPCError } from "@trpc/server";
import { type Context } from "./context";
import superjson from "superjson";
const t = initTRPC.context<Context>().create({
transformer: superjson,
errorFormatter({ shape }) {
return shape;
},
});
const isAuthed = t.middleware(({ next, ctx }) => {
if (!ctx.auth.userId) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Not authenticated" });
}
return next({
ctx: {
auth: ctx.auth,
},
});
});
export const router = t.router;
export const publicProcedure = t.procedure;
export const protectedProcedure = t.procedure.use(isAuthed);
Not on a laptop so can't browse the code very well
Is it a native BigInt?
If it's a custom thing you have to add your own serializer
Superjson handles BigInt well
It might also be that you're using some query cache lib where this error comes from

i am using trpc with prisma, and a wordpress database.
shema.prisma looks like:
lesson router looks like:
model wp_posts {
ID BigInt @id @default(autoincrement()) @db.UnsignedBigInt
post_author BigInt @default(0) @db.UnsignedBigInt
post_date DateTime @default(dbgenerated("'1970-01-01 00:00:00'")) @db.DateTime(0)
post_date_gmt DateTime @default(dbgenerated("'1970-01-01 00:00:00'")) @db.DateTime(0)
post_content String @db.LongText
post_title String @db.Text
post_excerpt String @db.Text
post_status String @default("publish") @db.VarChar(20)
comment_status String @default("open") @db.VarChar(20)
ping_status String @default("open") @db.VarChar(20)
post_password String @default("") @db.VarChar(255)
post_name String @default("") @db.VarChar(200)
to_ping String @db.Text
pinged String @db.Text
post_modified DateTime @default(dbgenerated("'1970-01-01 00:00:00'")) @db.DateTime(0)
post_modified_gmt DateTime @default(dbgenerated("'1970-01-01 00:00:00'")) @db.DateTime(0)
post_content_filtered String @db.LongText
post_parent BigInt @default(0) @db.UnsignedBigInt
guid String @default("") @db.VarChar(255)
menu_order Int @default(0)
post_type String @default("post") @db.VarChar(20)
post_mime_type String @default("") @db.VarChar(100)
comment_count BigInt @default(0)
@@index([post_author], map: "post_author")
@@index([post_name(length: 191)], map: "post_name")
@@index([post_parent], map: "post_parent")
@@index([post_type, post_status, post_date, ID], map: "type_status_date")
}
model wp_posts {
ID BigInt @id @default(autoincrement()) @db.UnsignedBigInt
post_author BigInt @default(0) @db.UnsignedBigInt
post_date DateTime @default(dbgenerated("'1970-01-01 00:00:00'")) @db.DateTime(0)
post_date_gmt DateTime @default(dbgenerated("'1970-01-01 00:00:00'")) @db.DateTime(0)
post_content String @db.LongText
post_title String @db.Text
post_excerpt String @db.Text
post_status String @default("publish") @db.VarChar(20)
comment_status String @default("open") @db.VarChar(20)
ping_status String @default("open") @db.VarChar(20)
post_password String @default("") @db.VarChar(255)
post_name String @default("") @db.VarChar(200)
to_ping String @db.Text
pinged String @db.Text
post_modified DateTime @default(dbgenerated("'1970-01-01 00:00:00'")) @db.DateTime(0)
post_modified_gmt DateTime @default(dbgenerated("'1970-01-01 00:00:00'")) @db.DateTime(0)
post_content_filtered String @db.LongText
post_parent BigInt @default(0) @db.UnsignedBigInt
guid String @default("") @db.VarChar(255)
menu_order Int @default(0)
post_type String @default("post") @db.VarChar(20)
post_mime_type String @default("") @db.VarChar(100)
comment_count BigInt @default(0)
@@index([post_author], map: "post_author")
@@index([post_name(length: 191)], map: "post_name")
@@index([post_parent], map: "post_parent")
@@index([post_type, post_status, post_date, ID], map: "type_status_date")
}
import { router, publicProcedure, protectedProcedure } from "../trpc";
import { z } from "zod";
export const lessonRouter = router({
all: publicProcedure.query(({ ctx }) => {
return ctx.prisma.wp_posts.findMany({
where: {
post_type: "sfwd-lessons",
},
});
}),
videoUri: publicProcedure.input(z.bigint()).query(({ ctx, input }) => {
return ctx.prisma.wp_postmeta.findFirst({
where: {
post_id: input, // Change the post_id value here
meta_key: "app_video_uri", // Replace "video_uri" with the actual meta_key for the meta_value you want to retrieve
},
});
}),
});
import { router, publicProcedure, protectedProcedure } from "../trpc";
import { z } from "zod";
export const lessonRouter = router({
all: publicProcedure.query(({ ctx }) => {
return ctx.prisma.wp_posts.findMany({
where: {
post_type: "sfwd-lessons",
},
});
}),
videoUri: publicProcedure.input(z.bigint()).query(({ ctx, input }) => {
return ctx.prisma.wp_postmeta.findFirst({
where: {
post_id: input, // Change the post_id value here
meta_key: "app_video_uri", // Replace "video_uri" with the actual meta_key for the meta_value you want to retrieve
},
});
}),
});
It looks right to me
If you want a quick ugly fix you can turn your BigInt into numbers or strings
Before returning them in the proc
Unsure why it's not working. I have a similar setup myself
in lesson router its ...input.(z.bigint()
and other places im using BigInt
does that matter?
if i try to use z.BigInt i get an error: "Property 'BigInt' does not exist on type"
Not really, if superjson is setup correctly it should work either way
Both for input and output
so where is the actual issue? in the trpc or prisma part?
since it goes trpc->prisma->db
if i change lessonRouter to:
so number rather than bigint, and then change the videoUri query with a hardcoded number I can get the proper videoUri in a console.log on the screen
so i have half the issue fixed, which was triggering the query based on the currently selected item. Now I seem to just be having an issue with bigint
videoUri: publicProcedure.input(z.number()).query(({ ctx, input }) => {
return ctx.prisma.wp_postmeta.findFirst({
where: {
post_id: input, // Change the post_id value here
meta_key: "app_video_uri", // Replace "video_uri" with the actual meta_key for the meta_value you want to retrieve
},
});
videoUri: publicProcedure.input(z.number()).query(({ ctx, input }) => {
return ctx.prisma.wp_postmeta.findFirst({
where: {
post_id: input, // Change the post_id value here
meta_key: "app_video_uri", // Replace "video_uri" with the actual meta_key for the meta_value you want to retrieve
},
});
const { data: videoData, error } = trpc.lesson.videoUri.useQuery(621, {
enabled: !!currentItem,
});
const { data: videoData, error } = trpc.lesson.videoUri.useQuery(621, {
enabled: !!currentItem,
});
trpc does a
JSON.stringify(xxx)
of the data sent and received
that will fail if xxx
contains anything that isn't standard json
if you use a data transformer it'll do JSON.stringify(transformer.serialize(xxx))
hmmm...ill look into making sure superjson is set up peoperly then, but its using the default setup for packages/api from t3-turbo:
I have "superjson": "^1.9.1", in package.json
its added to packages/api/src/trpc.ts
doing some tests now to ensure it's not on our end
im using "@trpc/client": "^10.1.0",
"@trpc/server": "^10.1.0",
yeah it's not on our end, just did a test
try upgrading trpc and superjson
trpc will give you type errors in later versions if you have setup the client wrong too
misconfig of transformers was so common so we made it into a type error if you did
should i use latest or a specifc version?
10.27.1?
latest
ok i changed all packages to ^10.27.1"
ran pnpm i
changed lesson router back to z.bigint
i changed the component query to what you suggested:
i am getting inline error:
and console error:
if I change component query to:
the inline error goes away but i am still getting the serialization console error
if i change to:
I get inline error:
as an update I added:
to the top of my coursecomponent file and it seems to have fixed the error
Reference: https://github.com/prisma/studio/issues/614#issuecomment-1186637811
videoUri: publicProcedure.input(z.bigint()).query(({ ctx, input }) => {
return ctx.prisma.wp_postmeta.findFirst({
where: {
post_id: input, // Change the post_id value here
meta_key: "app_video_uri", // Replace "video_uri" with the actual meta_key for the meta_value you want to retrieve
},
});
})
videoUri: publicProcedure.input(z.bigint()).query(({ ctx, input }) => {
return ctx.prisma.wp_postmeta.findFirst({
where: {
post_id: input, // Change the post_id value here
meta_key: "app_video_uri", // Replace "video_uri" with the actual meta_key for the meta_value you want to retrieve
},
});
})
const { data: videoData, error } = trpc.lesson.videoUri.useQuery(
currentItem?.ID as string,
{
enabled: !!currentItem?.ID,
},
);
const { data: videoData, error } = trpc.lesson.videoUri.useQuery(
currentItem?.ID as string,
{
enabled: !!currentItem?.ID,
},
);
Conversion of type 'bigint | undefined' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Type 'bigint' is not comparable to type 'string'.
Conversion of type 'bigint | undefined' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Type 'bigint' is not comparable to type 'string'.
TypeError: Do not know how to serialize a BigInt
TypeError: Do not know how to serialize a BigInt
const { data: videoData, error } = trpc.lesson.videoUri.useQuery(
currentItem?.ID as bigint,
{
enabled: !!currentItem?.ID,
},
);
const { data: videoData, error } = trpc.lesson.videoUri.useQuery(
currentItem?.ID as bigint,
{
enabled: !!currentItem?.ID,
},
);
const { data: videoData, error } = trpc.lesson.videoUri.useQuery(
currentItem?.ID,
{
enabled: !!currentItem?.ID,
},
);
const { data: videoData, error } = trpc.lesson.videoUri.useQuery(
currentItem?.ID,
{
enabled: !!currentItem?.ID,
},
);
No overload matches this call.
Overload 1 of 2, '(input: bigint, opts: DefinedUseTRPCQueryOptions<"lesson.videoUri", bigint, wp_postmeta | null, wp_postmeta | null, TRPCClientErrorLike<BuildProcedure<"query", { _config: RootConfig<{ ctx: { auth: SignedInAuthObject | SignedOutAuthObject; prisma: PrismaClient<...>; }; meta: object; errorShape: DefaultErrorShape; transformer: typeof SuperJSON; }>; ... 5 more ...; _output_out: typeof unsetMarker; }, wp_postmeta | null>>>): DefinedUseTRPCQueryResult<...>', gave the following error.
Argument of type 'bigint | undefined' is not assignable to parameter of type 'bigint'.
Type 'undefined' is not assignable to type 'bigint'.
Overload 2 of 2, '(input: bigint, opts?: UseTRPCQueryOptions<"lesson.videoUri", bigint, wp_postmeta | null, wp_postmeta | null, TRPCClientErrorLike<BuildProcedure<"query", { _config: RootConfig<{ ctx: { auth: SignedInAuthObject | SignedOutAuthObject; prisma: PrismaClient<...>; }; meta: object; errorShape: DefaultErrorShape; transformer: typeof SuperJSON; }>; ... 5 more ...; _output_out: typeof unsetMarker; }, wp_postmeta | null>>> | undefined): UseTRPCQueryResult<...>', gave the following error.
Argument of type 'bigint | undefined' is not assignable to parameter of type 'bigint'.
Type 'undefined' is not assignable to type 'bigint'.ts(2769)
No overload matches this call.
Overload 1 of 2, '(input: bigint, opts: DefinedUseTRPCQueryOptions<"lesson.videoUri", bigint, wp_postmeta | null, wp_postmeta | null, TRPCClientErrorLike<BuildProcedure<"query", { _config: RootConfig<{ ctx: { auth: SignedInAuthObject | SignedOutAuthObject; prisma: PrismaClient<...>; }; meta: object; errorShape: DefaultErrorShape; transformer: typeof SuperJSON; }>; ... 5 more ...; _output_out: typeof unsetMarker; }, wp_postmeta | null>>>): DefinedUseTRPCQueryResult<...>', gave the following error.
Argument of type 'bigint | undefined' is not assignable to parameter of type 'bigint'.
Type 'undefined' is not assignable to type 'bigint'.
Overload 2 of 2, '(input: bigint, opts?: UseTRPCQueryOptions<"lesson.videoUri", bigint, wp_postmeta | null, wp_postmeta | null, TRPCClientErrorLike<BuildProcedure<"query", { _config: RootConfig<{ ctx: { auth: SignedInAuthObject | SignedOutAuthObject; prisma: PrismaClient<...>; }; meta: object; errorShape: DefaultErrorShape; transformer: typeof SuperJSON; }>; ... 5 more ...; _output_out: typeof unsetMarker; }, wp_postmeta | null>>> | undefined): UseTRPCQueryResult<...>', gave the following error.
Argument of type 'bigint | undefined' is not assignable to parameter of type 'bigint'.
Type 'undefined' is not assignable to type 'bigint'.ts(2769)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(BigInt.prototype as any).toJSON = function () {
return Number(this);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(BigInt.prototype as any).toJSON = function () {
return Number(this);
};
Might be that react native doesn't support BigInt too
i accepted a solution to my og problem that this thread was titled after. I am still trying to address the issue with BigInts
Looking for more? Join the community!
T
tRPC
[How To] Properly use trpc UseQuery based on currently selected item
T
tRPC
[How To] Properly use trpc UseQuery based on currently selected item
Recommended Posts
Data from useQuery is inferred as data: {} | undefinedMy server query returns data from database via ElectroDB. TypeScript can statically infer all properCannot access 't' before initializationHi,
I'm migrating my app to a mono repo but I just can't get past this error for some reason `CannottRPC Middleware consuming memory limit on VercelHi all, I'm running into a weird error where my tRPC middleware to enforce that a user is authed, isUsing react-query parameters in tRPC for useQueryHello, the useQuery from react-query can take parameters such cacheTime, staleTime, refetchOnWindowFtRPC type error on turborepo```Types of property 'query' are incompatible.
Type 'inferHandlerFn<{}>' is not assignable to tyStack for expo?Can someone recommend a stack for an expo project? I'm considering trpc + fastify + fly.io, but havImplementing a "Prisma model converter middleware"Bit of a fancy name, but if you've ever worked with Symfonys param converters (especially the DoctriSenior Full Stack Developer is Ready.✍️ Skill Set
HTML/CSS/JS, TS
React/Next.js, Angular/RxJs, Tailwind CSS
WoSuggested way to invalidate queries on a component that is used on multiple pages.Please suggest me a way I can handle the following situation in the best possinle manner.
CoinsiderSetting up trpc behind AWS API gateway and authorizing using a lambdaCurrent setup:
- trpc api, containing both public an private procedures. Let's call them `posts.listsetMutationDefaults for optimistic updatesI have a `preferences` router, with a `get` query and a `set` mutation. I had optimistic updates setUsing tRPC in React SPA with Django backendis that possible? Do I need to create an AppRouter and put that inside my django backend files? How Typing a shared TRPC provider for testingContext:
- We have a monorepo with several micro-frontends which use Next.
- We're moving to using tResponse promise resolves before endpoint finished processingI want to interact with OpenAI's API in my Next.js + tRPC app. It seems that the my frontend is not tRPC onErrorI am using tRPC with Fastify and would like to be able to report issues when we get an error.
httpsCode structure for a large monorepo using nx + tRPCWe have a large monorepo with a single tRPC API that will be used by several web clients and other cDoes tRPC work with Clerk and Vercel Edge functions?So the answer is yes, at least locally, but I when I deploy to Vercel I get nothing. Trying to work TRPCClientError when creating a db entry without `updatedAt` value?Guys, this is my prisma schema:
```
model User {
id Int @id @default(autoincrement())
Type error: The inferred type of 'trpc' cannot be named without a reference....```./src/lib/api.ts:21:14
@driveorg/dashboard:build: Type error: The inferred type of 'trpc' cannot Decision on authI am using create-t3-app for my app , with next-auth (twitter, discord, google) . Now i am using sam