VVibeFlui

React Query

Generated UI previewREACT QUERY

React Query users

#ActionsEmailStatus
No data available.
Page 1 of 1 · Total: 0

List, create, edit, and delete all run through a real QueryClient (caching + automatic invalidation on mutation) — only the REST call underneath is swapped for an in-memory mock since this docs site has no backend.

@vibeflui/react-query registers a TanStack Query-compatible data provider. It does not render fields or table cells — it changes how list/detail/create/update/delete/action operations are executed, adding caching and automatic invalidation on top of the base provider (REST by default).

Install:

BASH
npm install @vibeflui/react-query @tanstack/react-query

File structure

TXT
schemas/
  users/
    react-query-users.schema.ts
lib/
  vibeflui/
    registry.tsx
app/
  users/
    page.tsx

Schema file

schemas/users/react-query-users.schema.ts

TS
export const reactQueryUsersSchema = {
  resource: "users",
  mode: "server",
  identity: { key: "id", param: "id" },
  endpoint: {
    list: "/api/users",
    create: { url: "/api/users", method: "POST" },
    update: { url: "/api/users/:id", method: "PATCH" },
    delete: { url: "/api/users/:id", method: "DELETE" }
  },
  provider: {
    type: "custom",
    name: "reactQuery"
  },
  table: {
    dataPath: "data",
    totalPath: "total",
    columns: [
      { key: "name", label: "Name", searchable: true, sortable: true },
      { key: "email", label: "Email", searchable: true },
      { key: "status", label: "Status" }
    ],
    search: { enabled: true, param: "search" },
    pagination: { enabled: true, pageSize: 10, pageParam: "page", pageSizeParam: "pageSize" },
    sort: { enabled: true, defaultKey: "name", defaultDirection: "asc" }
  },
  form: {
    mode: "modal",
    fields: [
      { name: "name", label: "Name", required: true },
      { name: "email", label: "Email", type: "email", required: true },
      {
        name: "status",
        type: "select",
        options: [
          { label: "Active", value: "active" },
          { label: "Pending", value: "pending" }
        ]
      }
    ]
  },
  actions: {
    create: { enabled: true, label: "Create user" },
    edit: { enabled: true },
    delete: { enabled: true, confirm: true, variant: "danger" }
  }
} as const;

provider.name: "reactQuery" must match the plugin's providerName (defaults to "reactQuery"). endpoint is still needed — the plugin's provider calls the base REST provider underneath, it just wraps it with query caching and invalidation.

Registry file

lib/vibeflui/registry.tsx

TSX
import { QueryClient } from "@tanstack/react-query";
import { createReactQueryPlugin } from "@vibeflui/react-query";

export const queryClient = new QueryClient();
export const reactQueryPlugin = createReactQueryPlugin({ queryClient });

Page file

app/users/page.tsx

TSX
"use client";

import { QueryClientProvider } from "@tanstack/react-query";
import { FluiKit, FluiKitProvider } from "@vibeflui/core";
import { queryClient, reactQueryPlugin } from "@/lib/vibeflui/registry";
import { reactQueryUsersSchema } from "@/schemas/users/react-query-users.schema";

export default function UsersPage() {
  return (
    <QueryClientProvider client={queryClient}>
      <FluiKitProvider plugins={[reactQueryPlugin]}>
        <FluiKit schema={reactQueryUsersSchema} />
      </FluiKitProvider>
    </QueryClientProvider>
  );
}

The page needs both QueryClientProvider (from @tanstack/react-query, so the rest of the app can also use useQuery/useMutation) and FluiKitProvider with the plugin registered.

Query behavior

Read operations use ensureQueryData when available, then fetchQuery, then the base provider directly. Mutation operations run through the base provider and invalidate queries afterward unless invalidateOnMutation is false.

TS
export const reactQueryPlugin = createReactQueryPlugin({
  queryClient,
  providerName: "adminQuery",
  invalidateOnMutation: true,
  refetchOnMutation: true,
  queryKey: (context, operation) => ["admin", context.schema.resource, operation, context.params]
});

baseProvider can also be overridden — pass any FluiKitDataProvider (not just the default REST one) to wrap it with React Query's caching, e.g. a custom or in-memory provider.

Exports include createReactQueryPlugin, ReactQueryPlugin, createReactQueryProvider, defaultReactQueryKey, and defaultReactQueryInvalidationKey.