Models
Hooks to list, load, create and delete the models in a schema from React components.
These hooks return Model instances from @seedprotocol/sdk: the definitions of your content types, such as Post or Author, not the items stored under them. Use them in schema editors and admin screens. To work with items, see Items.
import { useModels, useModel, useCreateModel, useDestroyModel } from '@seedprotocol/react'The read hooks wait for the client to be ready before they query, and return an empty result with isLoading: false until then. useModels and useModel cache through React Query: outside SeedProvider they use a shared fallback client with Seed's defaults, and development builds log a warning, so keep them inside SeedProvider (which hooks need it). The Model class itself is covered in Model.
useModels and useModel hold the models they show while the component is mounted and release them when it unmounts or shows others. When a shown model is destroyed or evicted, they fetch again: the list drops it, and useModel returns undefined.
Where a hook takes a schema, you can pass the schema's name (its metadata.name, such as 'blog') or its schema file ID.
useModels
Lists the models in a schema and updates when one is added or deleted.
function useModels(schemaId: string | null | undefined): {
models: Model[]
isLoading: boolean
error: Error | null
}Parameters
| Name | Type | Description |
|---|---|---|
schemaId | string | null | undefined | Schema name or schema file ID. Pass null or undefined to load nothing |
Returns
| Field | Type | Description |
|---|---|---|
models | Model[] | The schema's models, including ones still being created. [] until loaded |
isLoading | boolean | true during the first load |
error | Error | null | The query's error, if Model.all() failed |
Example
import { useModels } from '@seedprotocol/react'
export function ModelList() {
const { models, isLoading, error } = useModels('blog')
if (isLoading) return <p>Loading models…</p>
if (error) return <p>{error.message}</p>
return (
<ul>
{models.map((model) => (
<li key={model.id ?? model.modelName}>{model.modelName}</li>
))}
</ul>
)
}The hook watches the schema's rows in the models table and refetches whenever the set of models changes, deletes included, so deleting the last model empties the list. While the table still has rows, a refetch that briefly returns no models keeps the previous list instead of flashing [], unless a model in that list has stopped.
useModel
Loads one model, either by schema and model name or by model file ID. The component re-renders when the model's state changes.
function useModel(
schemaIdOrModelId: string | null | undefined,
modelName?: string | null | undefined,
): {
model: Model | undefined
isLoading: boolean
error: Error | null
}Parameters
| Name | Type | Description |
|---|---|---|
schemaIdOrModelId | string | null | undefined | With modelName: the schema name or schema file ID. Without it: the model's file ID |
modelName | string | null | undefined | The model's name, such as 'Post'. Leave it out (or pass null) to look up by model file ID |
The two forms work differently:
| Call | Lookup |
|---|---|
useModel('blog', 'Post') | Finds Post in useModels('blog'). isLoading and error come from that list |
useModel(modelFileId) | Model.createById(modelFileId), from cache or the database |
Returns
| Field | Type | Description |
|---|---|---|
model | Model | undefined | The model, or undefined if it isn't found or hasn't loaded |
isLoading | boolean | true while loading |
error | Error | null | The lookup error, if any |
Example
import { useModel } from '@seedprotocol/react'
export function PostModelStatus() {
const { model, isLoading } = useModel('blog', 'Post')
if (isLoading) return null
return <p>{model ? `Post is ${model.status}` : 'No Post model'}</p>
}
export function ModelById({ modelFileId }: { modelFileId: string }) {
const { model, error } = useModel(modelFileId)
if (error) return <p>{error.message}</p>
return <p>{model?.modelName} in {model?.schemaName}</p>
}Whether modelName is set decides which form runs, so modelName can switch between null and a string while the component is mounted. While it's null, useModel('blog', selectedName) looks 'blog' up as a model file ID.
useCreateModel
Adds a model to a schema and tracks its progress.
function useCreateModel(): UseCreateModelReturn
type UseCreateModelReturn = {
create: (schemaName: string, modelName: string, options?: UseCreateModelOptions) => Model
isLoading: boolean
error: Error | null
resetError: () => void
}
type UseCreateModelOptions = {
modelFileId?: string
properties?: { [propertyName: string]: any }
}Both types are exported, as is UseDestroyModelReturn.
Parameters of create
| Name | Type | Default | Description |
|---|---|---|---|
schemaName | string | The schema to add the model to | |
modelName | string | The new model's name | |
options.modelFileId | string | A generated 10-character ID | Use a known model file ID instead of generating one. If a model with this ID is already loaded, create returns that instance |
options.properties | { [name]: definition } | {} | Property definitions to create with the model, in the code shape, such as { body: { dataType: 'Text' } }. See the property definition reference |
Returns
| Field | Type | Description |
|---|---|---|
create | function | Returns the model's instance synchronously. A new model is still loading |
isLoading | boolean | true from the call until the model's status is 'ready' or 'error'. A model that's already loaded clears it at once, and so does a throw |
error | Error | null | The error create threw, or, if the model's status turns 'error', the load's own error (Failed to create model if it isn't an Error) |
resetError | () => void | Clears error |
Note the argument order: the hook's create takes the schema first, create(schemaName, modelName), while the SDK's Model.create takes (modelName, schemaName). If either is empty, it sets error and throws Model name is required or Schema name is required.
Example
import { useCreateModel } from '@seedprotocol/react'
export function AddCommentModel() {
const { create, isLoading, error } = useCreateModel()
return (
<>
<button
disabled={isLoading}
onClick={() =>
create('blog', 'Comment', {
properties: {
body: { dataType: 'Text' },
post: { dataType: 'Relation', ref: 'Post' },
},
})
}
>
Add Comment model
</button>
{error && <p>{error.message}</p>}
</>
)
}useModels('blog') picks up the new model once it's written to the database.
A name already in the schema gets a number. If the schema already has a model with that name (compared case-insensitively) and you don't pass modelFileId, the SDK doesn't return the existing model. It creates another one with a numbered name: create('blog', 'post') next to Post makes post 1. Check useModels first if you want find-or-create.
useDestroyModel
Deletes a model and its property definitions from the local database. Items of the model aren't deleted; see destroy().
function useDestroyModel(): UseDestroyModelReturn
type UseDestroyModelReturn = {
destroy: (model: Model) => Promise<void>
isLoading: boolean
error: Error | null
resetError: () => void
}Returns
| Field | Type | Description |
|---|---|---|
destroy | (model: Model) => Promise<void> | Calls model.destroy(). Does nothing if model is falsy |
isLoading | boolean | true while destroy runs |
error | Error | null | Set if model.destroy() rejects |
resetError | () => void | Clears error |
Like the other destroy hooks, destroy sets error and rejects when model.destroy() fails, database failures included. Catch the promise.
import type { Model } from '@seedprotocol/sdk'
import { useDestroyModel } from '@seedprotocol/react'
export function DeleteModelButton({ model }: { model: Model }) {
const { destroy, isLoading, error } = useDestroyModel()
return (
<>
<button disabled={isLoading} onClick={() => destroy(model).catch(() => {})}>
Delete {model.modelName}
</button>
{error && <p>{error.message}</p>}
</>
)
}Related
- Model: the
Modelclass these hooks return - Model properties: hooks for a model's fields
- Schemas: hooks for the schemas that hold models
- Data model: how schemas, models and items relate