Skip to content

Client Hooks API Reference

BlocksWeb provides a comprehensive set of React hooks for fetching and managing data in your components.

Overview

All hooks are imported from @blocksweb/core/client:

typescript
import {
  usePage,
  usePages,
  useCollection,
  useCollectionRecord,
  useAsset,
  useBlocks,
} from '@blocksweb/core/client';

Page Hooks

usePage

Fetch a single page by slug or ID.

typescript
function usePage(slug: string): UseQueryResult<Page>

Example:

typescript
import { usePage } from '@blocksweb/core/client';

function PageComponent({ slug }: { slug: string }) {
  const { data: page, isLoading, error } = usePage(slug);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error loading page</div>;

  return (
    <div>
      <h1>{page.name}</h1>
      <p>{page.description}</p>
    </div>
  );
}

Returns:

typescript
{
  data?: {
    id: string;
    name: string;
    slug: string;
    description?: string;
    blocks: Block[];
    metadata: PageMetadata;
    status: 'draft' | 'published';
    createdAt: Date;
    updatedAt: Date;
  };
  isLoading: boolean;
  error: Error | null;
  refetch: () => void;
}

usePages

Fetch multiple pages with optional filtering.

typescript
function usePages(options?: PageQueryOptions): UseQueryResult<Page[]>

Options:

typescript
type PageQueryOptions = {
  status?: 'draft' | 'published' | 'all';
  limit?: number;
  offset?: number;
  sort?: 'name' | 'createdAt' | 'updatedAt';
  order?: 'asc' | 'desc';
};

Example:

typescript
const { data: pages } = usePages({
  status: 'published',
  limit: 10,
  sort: 'createdAt',
  order: 'desc'
});

usePublishedPages

Fetch all published pages (convenience wrapper).

typescript
function usePublishedPages(): UseQueryResult<Page[]>

Example:

typescript
const { data: publishedPages } = usePublishedPages();

return (
  <nav>
    {publishedPages?.map(page => (
      <a key={page.id} href={page.slug}>{page.name}</a>
    ))}
  </nav>
);

Collection Hooks

useCollection

Query a collection with filtering, sorting, and pagination.

typescript
function useCollection<T>(
  collectionName: string,
  query?: CollectionQuery
): UseQueryResult<T[]>

Query Options:

typescript
type CollectionQuery = {
  where?: Record<string, any>;
  limit?: number;
  offset?: number;
  sort?: string;
  order?: 'asc' | 'desc';
};

Example:

typescript
const { data: products } = useCollection('products', {
  where: { category: 'electronics', inStock: true },
  limit: 20,
  sort: 'price',
  order: 'asc'
});

useCollectionRecord

Fetch a single record by ID.

typescript
function useCollectionRecord<T>(
  collectionName: string,
  recordId: string
): UseQueryResult<T>

Example:

typescript
const { data: product } = useCollectionRecord('products', productId);

return (
  <div>
    <h2>{product?.name}</h2>
    <p>${product?.price}</p>
  </div>
);

useCollectionRecords

Fetch multiple records by IDs.

typescript
function useCollectionRecords<T>(
  collectionName: string,
  recordIds: string[]
): UseQueryResult<T[]>

Example:

typescript
const { data: products } = useCollectionRecords('products', [
  'prod_1',
  'prod_2',
  'prod_3'
]);

useInfiniteCollection

Infinite scroll pagination for collections.

typescript
function useInfiniteCollection<T>(
  collectionName: string,
  query?: CollectionQuery
): UseInfiniteQueryResult<T[]>

Example:

typescript
const {
  data,
  fetchNextPage,
  hasNextPage,
  isFetchingNextPage
} = useInfiniteCollection('blog', {
  limit: 10
});

return (
  <div>
    {data?.pages.map(page =>
      page.map(post => <BlogPost key={post.id} {...post} />)
    )}

    {hasNextPage && (
      <button onClick={() => fetchNextPage()} disabled={isFetchingNextPage}>
        {isFetchingNextPage ? 'Loading...' : 'Load More'}
      </button>
    )}
  </div>
);

useCollectionSearch

Full-text search across collection records.

typescript
function useCollectionSearch<T>(
  collectionName: string,
  searchTerm: string,
  options?: SearchOptions
): UseQueryResult<T[]>

Example:

typescript
const [search, setSearch] = useState('');
const { data: results } = useCollectionSearch('products', search, {
  fields: ['name', 'description'],
  limit: 10
});

return (
  <>
    <input value={search} onChange={e => setSearch(e.target.value)} />
    {results?.map(product => <ProductCard key={product.id} {...product} />)}
  </>
);

Asset Hooks

useAsset

Fetch a single asset by ID.

typescript
function useAsset(assetId: string): UseQueryResult<Asset>

Example:

typescript
const { data: asset } = useAsset(assetId);

return (
  <img
    src={asset?.url}
    alt={asset?.name}
    width={asset?.width}
    height={asset?.height}
  />
);

Asset Type:

typescript
type Asset = {
  id: string;
  name: string;
  filename: string;
  url: string;
  mimeType: string;
  size: number;
  width?: number;
  height?: number;
  createdAt: Date;
};

useAssets

Fetch multiple assets with filtering.

typescript
function useAssets(options?: AssetQueryOptions): UseQueryResult<Asset[]>

Example:

typescript
const { data: images } = useAssets({
  mimeType: 'image/*',
  limit: 50
});

useAssetsByIds

Fetch specific assets by their IDs.

typescript
function useAssetsByIds(assetIds: string[]): UseQueryResult<Asset[]>

Mutation Hooks

useCreateRecord

Create a new record in a collection.

typescript
function useCreateRecord<T>(
  collectionName: string
): UseMutationResult<T, Error, Partial<T>>

Example:

typescript
const createProduct = useCreateRecord('products');

const handleSubmit = async (data) => {
  try {
    const newProduct = await createProduct.mutateAsync(data);
    console.log('Created:', newProduct);
  } catch (error) {
    console.error('Failed:', error);
  }
};

useUpdateRecord

Update an existing record.

typescript
function useUpdateRecord<T>(
  collectionName: string,
  recordId: string
): UseMutationResult<T, Error, Partial<T>>

Example:

typescript
const updateProduct = useUpdateRecord('products', productId);

const handleUpdate = async (updates) => {
  await updateProduct.mutateAsync(updates);
};

useDeleteRecord

Delete a record.

typescript
function useDeleteRecord(
  collectionName: string,
  recordId: string
): UseMutationResult<void, Error>

Example:

typescript
const deleteProduct = useDeleteRecord('products', productId);

const handleDelete = async () => {
  if (confirm('Are you sure?')) {
    await deleteProduct.mutateAsync();
  }
};

Editor Hooks

These hooks are only available within the BlocksWeb editor.

useBlocks

Manage blocks on the current page.

typescript
function useBlocks(): {
  blocks: Block[];
  addBlock: (block: Block) => void;
  updateBlock: (id: string, updates: Partial<Block>) => void;
  deleteBlock: (id: string) => void;
  reorderBlocks: (ids: string[]) => void;
  selectedBlockId: string | null;
  selectBlock: (id: string | null) => void;
}

Example:

typescript
const { blocks, addBlock, deleteBlock, selectedBlockId } = useBlocks();

const handleAddHero = () => {
  addBlock({
    type: 'Hero',
    props: {
      title: 'New Hero',
      subtitle: 'Subtitle here'
    }
  });
};

useBlock

Get the current block context (must be used within a BlocksWeb component).

typescript
function useBlock(): Block | null

Example:

typescript
const MyComponent: IBlockswebComponent = () => {
  const block = useBlock();

  return <div data-block-id={block?.id}>...</div>;
};

usePageData

Access current page data and metadata.

typescript
function usePageData(): {
  page: Page;
  locale: string;
  setLocale: (locale: string) => void;
  metadata: PageMetadata;
  updateMetadata: (updates: Partial<PageMetadata>) => void;
}

useAutoSave

Monitor auto-save status.

typescript
function useAutoSave(): {
  isSaving: boolean;
  lastSaved: Date | null;
  error: Error | null;
}

Example:

typescript
const { isSaving, lastSaved } = useAutoSave();

return (
  <div className="editor-status">
    {isSaving ? 'Saving...' : `Last saved: ${lastSaved?.toLocaleTimeString()}`}
  </div>
);

Context Hooks

useBlocksweb

Access global BlocksWeb settings and configuration.

typescript
function useBlocksweb(): {
  settings: BlockswebSettings;
  isEditor: boolean;
  isPreview: boolean;
  apiKey: string;
  workspaceId: string;
}

Hook Options

Most hooks use React Query under the hood and support these options:

typescript
{
  enabled?: boolean;           // Whether to run the query
  refetchInterval?: number;    // Auto-refetch interval (ms)
  refetchOnWindowFocus?: boolean;
  staleTime?: number;          // How long data stays fresh (ms)
  cacheTime?: number;          // How long to cache (ms)
  onSuccess?: (data) => void;
  onError?: (error) => void;
}

Example:

typescript
const { data } = useCollection('products', query, {
  enabled: isLoggedIn,        // Only fetch if logged in
  refetchInterval: 30000,     // Refetch every 30 seconds
  staleTime: 5 * 60 * 1000,   // Consider fresh for 5 minutes
  onSuccess: (data) => {
    console.log('Fetched:', data.length, 'products');
  }
});

Error Handling

All hooks return error information:

typescript
const { data, error, isLoading, isError } = usePage(slug);

if (isError) {
  return <ErrorDisplay error={error} />;
}

Common error types:

typescript
type BlockswebError = {
  message: string;
  code: 'NOT_FOUND' | 'UNAUTHORIZED' | 'NETWORK_ERROR' | 'SERVER_ERROR';
  status?: number;
};

Optimistic Updates

For mutations, use optimistic updates:

typescript
const updateProduct = useUpdateRecord('products', productId);

const handleUpdate = async (updates) => {
  await updateProduct.mutateAsync(updates, {
    onMutate: async (newData) => {
      // Optimistically update the UI
      await queryClient.cancelQueries(['products', productId]);
      const previousData = queryClient.getQueryData(['products', productId]);
      queryClient.setQueryData(['products', productId], newData);
      return { previousData };
    },
    onError: (err, newData, context) => {
      // Revert on error
      queryClient.setQueryData(['products', productId], context?.previousData);
    }
  });
};

TypeScript Usage

All hooks are fully typed. Provide generic types for type safety:

typescript
type Product = {
  id: string;
  name: string;
  price: number;
  inStock: boolean;
};

const { data: products } = useCollection<Product>('products');
// `products` is typed as Product[]

const { data: product } = useCollectionRecord<Product>('products', id);
// `product` is typed as Product

Next Steps