stcobbe
stcobbe
CCConvex Community
Created by stcobbe on 10/15/2024 in #support-community
Recommended pattern for initializing useQuery with server loaded value
Hey folks, Is there a recommended NextJS-compatible pattern for initializing a useQuery hook with a result from the server so that initial page load is very snappy but subsequent changes are fully reactive? (I realize this involves double fetching) e.g.
export default async function ChatServer({
chatId,
}: {
chatId: ChatId | null;
}) {
const initialMessages = chatId
? await fetchQuery(api.chats.listMessagesByChatId, {
chatId,
})
: undefined;
return (
<ChatClient
initialChatId={chatId}
initialMessages={initialMessages}
/>
);
}
export default async function ChatServer({
chatId,
}: {
chatId: ChatId | null;
}) {
const initialMessages = chatId
? await fetchQuery(api.chats.listMessagesByChatId, {
chatId,
})
: undefined;
return (
<ChatClient
initialChatId={chatId}
initialMessages={initialMessages}
/>
);
}
export default function ChatClient({
initialChatId,
initialMessages,
}: {
initialChatId: ChatId | null;
initialMessages?: ChatMessage[];
}) {
const messages = useQueryWithInit(
api.chats.listMessagesByChatId,
initialMessages,
chatId ? { chatId } : "skip",
);

return (
<>
<div className="w-full h-full flex flex-col">
<Content
messages={messages}
/>
</div>
</>
);
}
export default function ChatClient({
initialChatId,
initialMessages,
}: {
initialChatId: ChatId | null;
initialMessages?: ChatMessage[];
}) {
const messages = useQueryWithInit(
api.chats.listMessagesByChatId,
initialMessages,
chatId ? { chatId } : "skip",
);

return (
<>
<div className="w-full h-full flex flex-col">
<Content
messages={messages}
/>
</div>
</>
);
}
Here's a hypothetical implementation of such a function:
export function useQueryWithInit<T extends FunctionReference<"query">>(
queryFunction: T,
initialValue: FunctionReturnType<T> | undefined,
...args: OptionalRestArgsOrSkip<T>
): FunctionReturnType<T> | undefined {
const queryResult = useQuery(queryFunction, ...args);

const hasReceivedValue = useRef(false);

if (args[0] === "skip") {
return null;
}

if (queryResult !== undefined) {
// Mark that we've received a value
hasReceivedValue.current = true;
// Return the query result immediately
return queryResult;
}

if (!hasReceivedValue.current) {
return initialValue;
}

return undefined;
}
export function useQueryWithInit<T extends FunctionReference<"query">>(
queryFunction: T,
initialValue: FunctionReturnType<T> | undefined,
...args: OptionalRestArgsOrSkip<T>
): FunctionReturnType<T> | undefined {
const queryResult = useQuery(queryFunction, ...args);

const hasReceivedValue = useRef(false);

if (args[0] === "skip") {
return null;
}

if (queryResult !== undefined) {
// Mark that we've received a value
hasReceivedValue.current = true;
// Return the query result immediately
return queryResult;
}

if (!hasReceivedValue.current) {
return initialValue;
}

return undefined;
}
23 replies
CCConvex Community
Created by stcobbe on 7/8/2024 in #support-community
Self-reference in validators
Hi folks, Is it possible to somehow use self-references in validators, e.g.:
export const folderValidator = v.object({
id: v.number(),
files: v.array(fileValidator),
subFolders: v.array(folderValidator),
});
export const folderValidator = v.object({
id: v.number(),
files: v.array(fileValidator),
subFolders: v.array(folderValidator),
});
Doing this now results in TypeScript error Variable 'folderValidator' is used before being assigned. Please let me know if I can provide additional context. Thank you!
3 replies
CCConvex Community
Created by stcobbe on 1/15/2024 in #support-community
Self-hosted support
Hi folks, I know this has been asked multiple times in the past but I wanted to check in on the progress of Convex support for a self-hosted offering. Our decision to use Convex basically comes down to self-hosted support and I'm trying to gauge if you think it'll ship in Q1/Q2 or H1/H2. Thank you!
12 replies