{
    "format": "skill/v1",
    "skill_id": "waynesutton-convexskills-skills-convex-realtime-skill-md",
    "name": "convex-realtime",
    "version": "1.0.0",
    "description": "Patterns for building reactive apps including subscription management, optimistic updates, cache behavior, and paginated queries with cursor-based loading",
    "category": [
        "开发编程"
    ],
    "trigger_words": [],
    "tags": [
        "react"
    ],
    "source": "DeepseekModel",
    "source_url": "https://deepseekmodel.com/skill?id=waynesutton-convexskills-skills-convex-realtime-skill-md",
    "exported_at": "2026-09-20T03:24:37+08:00",
    "system_prompt": "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 ();",
    "model_config": {
        "provider": "deepseek",
        "model": "deepseek-chat",
        "temperature": 0.7,
        "max_tokens": 4096,
        "top_p": 0.9
    },
    "examples": [
        {
            "input": "请用convex-realtime帮我处理问题",
            "output": "好的，我是convex-realtime。Patterns for building reactive apps including subscription management, optimistic updates, cache behavior, and paginated queries with cursor-based loading 我会根据你的需求提供专业帮助。"
        },
        {
            "input": "介绍一下你的能力",
            "output": "我是convex-realtime，专注于开发编程领域。Patterns for building reactive apps including subscription management, optimistic updates, cache behavior, and paginated queries with cursor-based loading"
        }
    ],
    "install_guide": {
        "coze": "在 Coze 平台创建 Bot -> 技能配置 -> 导入此 .skill 文件",
        "dify": "在 Dify 平台创建应用 -> 添加知识库 -> 导入此 .skill 配置",
        "claude": "将 system_prompt 字段内容复制到 Claude 自定义指令中",
        "custom": "将此 .skill 文件加载到你的 AI Agent 框架中，解析 system_prompt 和 model_config 即可使用"
    }
}