Skills Plugins MCP Prompt Model 博客 我的中心

convex-realtime

Patterns for building reactive apps including subscription management, optimistic updates, cache behavior, and paginated queries with cursor-based loading

DeepseekModel Curated skill Quality Excellent · 78 v1.0.0

Get

https://deepseekmodel.com/api/download.php?id=waynesutton-convexskills-skills-convex-realtime-skill-md&format=skill
Download .skill Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name convex-realtime displayName Convex Realtime description Patterns for building reactive apps including subscription management, optimistic updates, cache behavior, and paginated queries with cursor-based loading version 1.0.0 author Convex tags ["convex","realtime","subscriptions","optimistic-updates","pagination"] Convex Realtime Build reactive applications with Convex's real-time subscriptions, optimistic updates, intelligent caching, and cursor-based pagination. Documentation Sources Before implementing, do not assume; fetch the latest documentation: Primary: https://docs.convex.dev/client/react Optimistic Updates: https://docs.convex.dev/client/react/optimistic-updates Pagination: https://docs.convex.dev/database/pagination For broader context: https://docs.convex.dev/llms.txt Instructions How Convex Realtime Works Automatic Subscriptions - useQuery creates a subscription that updates automatically Smart Caching - Query results are cached and shared across components Consistency - All subscriptions see a consistent view of the database Efficient Updates - Only re-renders when relevant data changes Basic Subscriptions // React component with real-time data import { useQuery } from "convex/react" ; import { api } from "../convex/_generated/api" ; function TaskList ( { userId }: { userId: Id< "users" > } ) { // Automatically subscribes and updates in real-time const tasks = useQuery (api. tasks . list , { userId }); if (tasks === undefined ) { return < div > Loading... </ div > ; } return ( < ul > {tasks.map((task) => ( < li key = {task._id} > {task.title} </ li > ))} </ ul > ); } Conditional Queries import { useQuery } from "convex/react" ; import { api } from "../convex/_generated/api" ; function UserProfile ( { userId }: { userId: Id< "users" > | null } ) { // Skip query when userId is null const user = useQuery ( api. users . get , userId ? { userId } : "skip" ); if (userId === null ) { return < div > Select a user </ div > ; } if (user === undefined ) { return < div > Loading... </ div > ; } return < div > {user.name} </ div > ; } Mutations with Real-time Updates import { useMutation, useQuery } from "convex/react" ; import { api } from "../convex/_generated/api" ; function TaskManager ( { userId }: { userId: Id< "users" > } ) { const tasks = useQuery (api. tasks . list , { userId }); const createTask = useMutation (api. tasks . create ); const toggleTask = useMutation (api. tasks . toggle ); const handleCreate = async ( title : string ) => { // Mutation triggers automatic re-render when data changes await createTask ({ title, userId }); }; const handleToggle = async ( taskId : Id < "tasks" > ) => { await toggleTask ({ taskId }); }; return ( < div > < button onClick = {() => handleCreate("New Task")}>Add Task </ button > < ul > {tasks?.map((task) => ( < li key = {task._id} onClick = {() => handleToggle(task._id)}> {task.completed ? "✓" : "○"} {task.title} </ li > ))} </ ul > </ div > ); } Optimistic Updates Show changes immediately before server confirmation: import { useMutation, useQuery } from "convex/react" ; import { api } from "../convex/_generated/api" ; import { Id } from "../convex/_generated/dataModel" ; function TaskItem ( { task }: { task: Task } ) { const toggleTask = useMutation (api. tasks . toggle ). withOptimisticUpdate ( ( localStore, args ) => { const { taskId } = args; const currentValue = localStore. getQuery (api. tasks . get , { taskId }); if (currentValue !== undefined ) { localStore. setQuery (api. tasks . get , { taskId }, { ...currentValue, completed : !currentValue. completed , }); } } ); return ( < div onClick = {() => toggleTask({ taskId: task._id })}> {task.completed ? "✓" : "○"} {task.title} </ div > ); } Optimistic Updates for Lists import { useMutation } from "convex/react" ; import { api } from "../convex/_generated/api" ; function useCreateTask ( userId : Id < "users" > ) { return useMutation (api. tasks . create ). withOptimisticUpdate ( ( localStore, args ) => { const { title, userId } = args; const currentTasks = localStore. getQuery (api. tasks . list , { userId }); if (currentTasks !== undefined ) { // Add optimistic task to the list const optimisticTask = { _id : crypto. randomUUID () as Id < "tasks" >, _creationTime : Date . now (), title, userId, completed : false , }; localStore. setQuery (api. tasks . list , { userId }, [ optimisticTask, ...currentTasks, ]); } } ); } Cursor-Based Pagination // convex/messages.ts import { query } from "./_generated/server" ; import { v } from "convex/values" ; import { paginationOptsValidator } from "convex/server" ; export const listPaginated = query ({ args : { channelId : v. id ( "channels" ), paginationOpts : paginationOptsValidator, }, handler : async (ctx, args) => { return await ctx. db . query ( "messages" ) . withIndex ( "by_channel" , ( q ) => q. eq ( "channelId" , args. channelId )) . order ( "desc" ) . paginate (args. paginationOpts ); }, }); // React component with pagination import { usePaginatedQuery } from "convex/react" ; import { api } from "../convex/_generated/api" ; function MessageList ( { channelId }: { channelId: Id< "channels" > } ) { const { results, status, loadMore } = usePaginatedQuery ( api. messages . listPaginated , { channelId }, { initialNumItems : 20 } ); return ( < div > {results.map((message) => ( < div key = {message._id} > {message.content} </ div > ))} {status === "CanLoadMore" && ( < button onClick = {() => loadMore(20)}>Load More </ button > )} {status === "LoadingMore" && < div > Loading... </ div > } {status === "Exhausted" && < div > No more messages </ div > } </ div > ); } Infinite Scroll Pattern import { usePaginatedQuery } from "convex/react" ; import { useEffect, useRef } from "react" ; import { api } from "../convex/_generated/api" ; function InfiniteMessageList ( { channelId }: { channelId: Id< "channels" > } ) { const { results, status, loadMore } = usePaginatedQuery ( api. messages . listPaginated , { channelId }, { initialNumItems : 20 } ); const observerRef = useRef< IntersectionObserver >(); const loadMoreRef = useRef< HTMLDivElement >( null ); useEffect ( () => { if (observerRef. current ) { observerRef. current . disconnect (); } observerRef. current = new IntersectionObserver ( ( entries ) => { if (entries[ 0 ]. isIntersecting && status === "CanLoadMore" ) { loadMore ( 20 ); } }); if (loadMoreRef. current ) { observerRef. current . observe (loadMoreRef. current ); } return () => observerRef. current ?. disconnect (); }, [status, loadMore]); return ( < div > {results.map((message) => ( < div key = {message._id} > {message.content} </ div > ))} < div ref = {loadMoreRef} style = {{ height: 1 }} /> {status === "LoadingMore" && < div > Loading... </ div > } </ div > ); } Multiple Subscriptions import { useQuery } from "convex/react" ; import { api } from "../convex/_generated/api" ; function Dashboard ( { userId }: { userId: Id< "users" > } ) { // Multiple subscriptions update independently const user = useQuery (api. users . get , { userId }); const tasks = useQuery (api. tasks . list , { userId }); const notifications = useQuery (api. notifications . unread , { userId }); const isLoading = user === undefined || tasks === undefined || notifications === undefined ; if (isLoading) { return < div > Loading... </ div > ; } return ( < div > < h1 > Welcome, {user.name} </ h1 > < p > You have {tasks.length} tasks </ p > < p > {notifications.length} unread notifications </ p > </ div > ); } Examples Real-time Chat Application // convex/messages.ts import { query, mutation } from "./_generated/server" ; import { v } from "convex/values" ; export const list = query ({ args : { channelId : v. id ( "channels" ) }, returns : v. array (v. object ({ _id : v. id ( "messages" ), _creationTime : v. number (), content : v. string (), authorId : v. id ( "users" ), authorName : v. string (), })), handler : async (ctx, args) => { const messages = await ctx. db . query ( "messages" ) . withIndex ( "by_channel" , ( q ) => q. eq ( "channelId" , args. channelId )) . order ( "desc" ) . take ( 100 ); // Enrich with author names return Promise . all ( messages. map ( async (msg) => { const author = await ctx. db . get (msg. authorId ); return { ...msg, authorName : author?. name ?? "Unknown" , }; }) ); }, }); export const send = mutation ({ args : { channelId : v. id ( "channels" ), authorId : v. id ( "users" ), content : v. string (), }, returns : v. id ( "messages" ), handler : async (ctx, args) => { return await ctx. db . insert ( "messages" , { channelId : args. channelId , authorId : args. authorId , content : args. content , }); }, }); // ChatRoom.tsx import { useQuery, useMutation } from "convex/react" ; import { api } from "../convex/_generated/api" ; import { useState, useRef, useEffect } from "react" ; function ChatRoom ( { channelId, userId }: Props ) { const messages = useQuery (api. messages . list , { channelId }); const sendMessage = useMutation (api. messages . send ); const [input, setInput] = useState ( "" ); const messagesEndRef = useRef< HTMLDivElement >( null ); // Auto-scroll to bottom on new messages useEffect ( () => { messagesEndRef. current ?. scrollIntoView ({ behavior : "smooth" }); }, [messages]); const handleSend = async ( e : React . FormEvent ) => { e. preventDefault ();
Keywords that activate this skill. Click one to copy it.

This skill does not provide trigger words.

The downloaded .skill package contains the following fields.
Field Description
formatFormat tag (skill/v1)
skill_idUnique skill ID
nameSkill name
versionVersion
descriptionDescription
categoryCategories (array)
trigger_wordsTrigger words
tagsTags
sourceSource
source_urlSource URL (this page)
exported_atExported at (set per download)
system_promptSystem prompt body
model_configModel config: provider / model / temperature / max_tokens / top_p
examplesExamples
install_guideImport guide for Coze / Dify / Claude / custom frameworks
The same skill can be exported in different platform formats.
.skill Standard format with system_prompt and model_config, ready for any agent framework Download
.skillpro Enhanced format with scripts, tools, dependencies and hooks Download
.json Plain JSON export with system_prompt and model parameters only Download
Coze Markdown with frontmatter, for Coze platform import Download
Dify Dify DSL, import directly after creating an app Download

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。