mcpField
S
studio-queries

studio-queries

github.com/supabase开发114.3k215 次安装今天更新
代码仓库

关于 studio-queries

一项介绍 Studio 数据代码中 React Query 模式的开发技能,涵盖类型化查询选项、查询键、变更钩子和组件加载状态。

主要功能

  1. 01定义领域专属查询键
  2. 02创建类型化查询选项
  3. 03支持命令式查询数据获取
  4. 04构建带缓存失效的变更钩子
  5. 05统一呈现等待、错误和成功状态

适用场景

  1. 01为 Studio 添加数据查询
  2. 02在 React 组件外获取查询数据
  3. 03实现带缓存更新的变更操作
  4. 04一致地处理加载和错误状态

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/supabase/supabase --skill studio-queries

安装后在 Claude Code 中输入/studio-queries确认已加载。

详细介绍

Studio 查询与变更(React Query)

遵循 apps/studio/data/ 中的模式。参考示例:

  • 查询选项:apps/studio/data/table-editor/table-editor-query.ts
  • 变更钩子:apps/studio/data/edge-functions/edge-functions-update-mutation.ts
  • 键:apps/studio/data/edge-functions/keys.ts

查询键

为每个领域定义一个 keys.ts。使用带有 as const 的数组键导出 *Keys 辅助函数。切勿在组件中内联查询键。

export const edgeFunctionsKeys = {
  list: (projectRef: string | undefined) => ['projects', projectRef, 'edge-functions'] as const,
  detail: (projectRef: string | undefined, slug: string | undefined) =>
    ['projects', projectRef, 'edge-function', slug, 'detail'] as const,
}

查询选项(推荐模式)

使用 @tanstack/react-query 中的 queryOptions。这样既有类型安全,也可同时用于 useQuery() 和 queryClient.fetchQuery()。

规则:

  • 导出 XVariables、XData 和 XError 类型(以领域名称为前缀)
  • 实现一个私有的 getX(variables, signal?) 函数:
    • 如果缺少必需变量,则抛出错误
    • 传入 signal 以支持取消
    • 失败时调用 handleError(error)(该函数会抛出错误);成功时返回 data
    • 不导出此函数——命令式获取时使用 queryClient.fetchQuery(xQueryOptions(...))
  • 使用 queryOptions 导出 xQueryOptions()
  • 使用 enabled 控制查询,确保必需变量存在后才运行
  • 仅限平台的查询:在 enabled 中包含 lib/constants 中的 IS_PLATFORM
  • 不要向 xQueryOptions 添加额外参数——调用方通过解构覆盖:{ ...xQueryOptions(vars), enabled: true }
import { queryOptions } from '@tanstack/react-query'

import { xKeys } from './keys'
import { get, handleError } from '@/data/fetchers'
import { IS_PLATFORM } from '@/lib/constants'
import { ResponseError } from '@/types'

export type XVariables = { projectRef?: string }
export type XError = ResponseError

async function getX({ projectRef }: XVariables, signal?: AbortSignal) {
  if (!projectRef) throw new Error('projectRef is required')
  const { data, error } = await get('/v1/projects/{ref}/x', {
    params: { path: { ref: projectRef } },
    signal,
  })
  if (error) handleError(error)
  return data
}

export type XData = Awaited<ReturnType<typeof getX>>

export const xQueryOptions = ({ projectRef }: XVariables) =>
  queryOptions({
    queryKey: xKeys.list(projectRef),
    queryFn: ({ signal }) => getX({ projectRef }, signal),
    enabled: IS_PLATFORM && typeof projectRef !== 'undefined',
  })

在组件中使用查询选项

import { useQuery } from '@tanstack/react-query'

import { xQueryOptions } from '@/data/x/x-query'

const { data, isPending, isError } = useQuery(xQueryOptions({ projectRef: project?.ref }))

命令式获取(在 React 外部或回调中)

const queryClient = useQueryClient()
const { data: project } = useSelectedProjectQuery()

const handleClick = useCallback(
  async (id: number) => {
    const data = await queryClient.fetchQuery(xQueryOptions({ id, projectRef: project?.ref }))
    // use data...
  },
  [project?.ref, queryClient]
)

变更钩子

  • 导出一个包含 projectRef、标识符和 payload 的 Variables 类型
  • 实现一个私有的 updateX(vars) 函数,进行必需变量校验并调用 handleError
  • 将其封装在 useXMutation() 中:
    • 接受 UseMutationOptions(省略 mutationFn)
    • 在 onSuccess 中使用 await Promise.all([...]) 使 list() 和 detail() 键失效
    • 未提供 onError 时,默认调用 toast.error(...)
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'

import { xKeys } from './keys'

type XUpdateVariables = { projectRef: string; slug: string; payload: XPayload }

export const useXUpdateMutation = ({
  onSuccess,
  onError,
  ...options
}: UseMutationOptions<XData, XError, XUpdateVariables> = {}) => {
  const queryClient = useQueryClient()
  return useMutation({
    mutationFn: updateX,
    async onSuccess(data, variables, context) {
      await Promise.all([
        queryClient.invalidateQueries({
          queryKey: xKeys.detail(variables.projectRef, variables.slug),
        }),
        queryClient.invalidateQueries({ queryKey: xKeys.list(variables.projectRef) }),
      ])
      await onSuccess?.(data, variables, context)
    },
    async onError(error, variables, context) {
      if (onError === undefined) toast.error(`Failed to update: ${error.message}`)
      else onError(error, variables, context)
    },
    ...options,
  })
}

组件用法

  • 使用 React Query v5 标志:初次加载时使用 isPending,后台重新获取时使用 isFetching
  • 按顺序明确渲染各状态:待处理 → 错误 → 成功

评论

支持 Markdown