Seed Protocol
@seedprotocol/react

Schemas

Hooks to list, load, create and delete Seed schemas from React components, for schema editors and admin screens.

These hooks return Schema instances from @seedprotocol/sdk. Most apps never need them: you pass your schema to the client in config.schema and work with items. Reach for them when you build a schema editor or an admin view of the schemas on the device.

import {
  useSchemas,
  useSchema,
  useCreateSchema,
  useDestroySchema,
  useAllSchemaVersions,
  useSeedProtocolSchema,
} from '@seedprotocol/react'

All of them wait for the client to be ready before they query. Until then, useSchemas returns [] with isLoading: false, useSchema returns schema: null with isLoading: false (after a first render at true when you pass an identifier), and useAllSchemaVersions returns undefined. Only useSchemas uses React Query: outside SeedProvider it falls back to a shared client with Seed's defaults, and development builds log a warning, so keep it inside SeedProvider (which hooks need it). The Schema class itself (its getters, validate(), saveNewVersion() and so on) is covered in Schema.

useSchemas

Lists the latest version of each schema on the device.

function useSchemas(): {
  schemas: Schema[]
  isLoading: boolean
  error: Error | null
}

Returns

FieldTypeDescription
schemasSchema[]One instance per schema name, at its latest version, from Schema.all(). The SDK's internal Seed Protocol schema is left out. [] until loaded
isLoadingbooleantrue during the first load
errorError | nullThe query's error, if Schema.all() failed

useSchemas caches its result in React Query under ['seed', 'schemas']. It refetches when a schema is written to the database or deleted from it. While mounted, it holds each schema it lists, and fetches the list again when a listed schema is destroyed or evicted, or the client stops.

Example

import { useSchemas } from '@seedprotocol/react'

export function SchemaList() {
  const { schemas, isLoading, error } = useSchemas()
  if (isLoading) return <p>Loading schemas…</p>
  if (error) return <p>{error.message}</p>
  return (
    <ul>
      {schemas.map((schema) => (
        <li key={schema.id ?? schema.schemaName}>
          {schema.schemaName} (v{schema.version})
        </li>
      ))}
    </ul>
  )
}

useSchema

Loads one schema as a reactive Schema instance. Assigning to its tracked fields (schema.name = 'New name') saves a draft and re-renders components that use it; see Saving and conflicts.

function useSchema(schemaIdentifier: string | null | undefined): {
  schema: Schema | null
  isLoading: boolean
  error: Error | null
}

Parameters

NameTypeDescription
schemaIdentifierstring | null | undefinedA schema name (the latest version is used) or a schema file ID. Pass null or undefined to load nothing

Returns

FieldTypeDescription
schemaSchema | nullThe instance. null (not undefined) before the client is ready, with no identifier, when no schema has that name or ID, or when creating the instance throws
isLoadingbooleantrue while the hook checks that the schema exists and while the schema's status is 'loading'. false once it's 'ready' or 'error'
errorError | nullSet if creating the instance throws, or when the schema's status turns 'error' (its loading error, or Failed to load schema "<name>"). Cleared when it's 'ready'

The instance is shared: every useSchema('blog') gets the same object from the SDK's cache. Each hook holds it while mounted and releases its hold on unmount and when schemaIdentifier changes. A schema stays cached after its last hold is released, until it's destroyed or evicted or the client stops.

Example

import { useSchema } from '@seedprotocol/react'

export function SchemaTitle({ name }: { name: string }) {
  const { schema, isLoading } = useSchema(name)
  if (isLoading || !schema) return null
  return <h2>{schema.metadata?.name} has {schema.models.length} models</h2>
}

useSchema only loads schemas that exist: it checks the schemas table for the name or schema file ID first. For an unknown name, such as a typo, it returns schema: null with isLoading: false and error: null, and creates nothing. Use useCreateSchema to create one.

useCreateSchema

Creates a schema and tracks its progress.

function useCreateSchema(): {
  createSchema: (schemaName: string) => Schema
  isLoading: boolean
  error: Error | null
  resetError: () => void
}

Returns

FieldTypeDescription
createSchema(schemaName: string) => SchemaReturns the schema's instance synchronously. A new schema is still loading
isLoadingbooleantrue from the call until the schema's status is 'ready' or 'error'. A schema that's already loaded clears it at once, and so does a throw
errorError | nullThe error createSchema threw, or the schema's loading error if its status turns 'error'
resetError() => voidClears error

createSchema(name) goes through Schema.create(), so it's find-or-create: if a schema with that name exists, you get that one back instead of a new one. A new schema is saved as a local draft. If schemaName is empty, it sets error and throws Schema name is required.

Example

import { useCreateSchema } from '@seedprotocol/react'

export function NewSchemaButton() {
  const { createSchema, isLoading, error } = useCreateSchema()
  return (
    <>
      <button disabled={isLoading} onClick={() => createSchema('newsletter')}>
        {isLoading ? 'Creating…' : 'New schema'}
      </button>
      {error && <p>{error.message}</p>}
    </>
  )
}

Only the most recent call is tracked. Calling createSchema again stops tracking the previous schema.

useDestroySchema

Deletes a schema, with its models and properties, from the local database. unload and destroy lists what destroy() deletes and what it keeps.

function useDestroySchema(): UseDestroySchemaReturn

type UseDestroySchemaReturn = {
  destroy: (schema: Schema) => Promise<void>
  isLoading: boolean
  error: Error | null
  resetError: () => void
}

Returns

FieldTypeDescription
destroy(schema: Schema) => Promise<void>Calls schema.destroy(). Resolves when it's done. Does nothing if schema is falsy
isLoadingbooleantrue while destroy runs
errorError | nullSet if schema.destroy() rejects
resetError() => voidClears error

When schema.destroy() fails, including when the database delete fails, error is set and the promise rejects, so catch it.

Example

import type { Schema } from '@seedprotocol/sdk'
import { useDestroySchema } from '@seedprotocol/react'

export function DeleteSchemaButton({ schema }: { schema: Schema }) {
  const { destroy, isLoading, error, resetError } = useDestroySchema()
  return (
    <>
      <button disabled={isLoading} onClick={() => destroy(schema).catch(() => {})}>
        Delete
      </button>
      {error && <p onClick={resetError}>{error.message}</p>}
    </>
  )
}

useAllSchemaVersions

Loads a Schema instance for every schema name in the database.

function useAllSchemaVersions(): Schema[] | null | undefined

Returns

The array itself, not an object:

ValueMeaning
undefinedNot loaded yet (or the client isn't ready)
nullLoading failed
Schema[]One instance per schema name

Despite the name, you get one instance per schema, not one per version. Unlike useSchemas, it doesn't leave out the internal Seed Protocol schema. It loads once when the client is ready and doesn't refresh after that, so prefer useSchemas for lists. It holds each schema while mounted, and on unmount calls unload() on its instances, which releases only this hook's holds. The schemas stay cached after that.

import { useAllSchemaVersions } from '@seedprotocol/react'

export function AllSchemas() {
  const schemas = useAllSchemaVersions()
  if (schemas === undefined) return <p>Loading…</p>
  if (schemas === null) return <p>Could not load schemas</p>
  return <p>{schemas.map((s) => s.schemaName).join(', ')}</p>
}

useSeedProtocolSchema

Loads the SDK's internal Seed Protocol schema. It's the same as useSchema('Seed Protocol'), with the same return shape.

function useSeedProtocolSchema(): {
  schema: Schema | null
  isLoading: boolean
  error: Error | null
}

The SDK manages this schema. Read it (for example to show its version), but don't edit it.

import { useSeedProtocolSchema } from '@seedprotocol/react'

export function SeedProtocolVersion() {
  const { schema } = useSeedProtocolSchema()
  return <span>{schema?.version}</span>
}

On this page