Create and read items
Write an item to the local database from a React component, list a model's items, and show their property values as they change.
An item is one record of a model, such as a single post. Creating one writes it to the SQLite database the SDK runs in the browser. You don't need a wallet, and nothing is signed or uploaded: the item stays in the browser until you publish it, which is a separate step.
This page assumes you've followed Add Seed to your app, so your schema has a Post model with a title property and the components below render inside SeedProvider and SeedClientGate.
Create an item
useCreateItem gives you a createItem function. Pass it the model name and the property values, and the SDK saves a new item to the local database:
import { useState } from 'react'
import { useCreateItem } from '@seedprotocol/react'
export function NewPost() {
const { createItem, isLoading, error } = useCreateItem()
const [title, setTitle] = useState('')
const handleCreate = async () => {
if (!title.trim()) return
await createItem('Post', { title })
setTitle('')
}
return (
<div>
<input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Post title"
/>
<button onClick={handleCreate} disabled={isLoading}>
{isLoading ? 'Saving…' : 'Add post'}
</button>
{error && <p>Couldn't save: {error.message}</p>}
</div>
)
}createItem doesn't throw. If a value is invalid, such as a title over 255 characters, it saves nothing, returns undefined and puts the error in error. A call made while an earlier one is still running creates nothing: it returns the earlier call's promise, which resolves to that call's item whatever values the second call passed. The sample disables the button while isLoading is true, so a click during a save does nothing.
List a model's items
useItems returns the items of a model and re-renders when items are added or removed. To show a property value that stays current, each row uses useItemProperty, which subscribes to one property of one item:
import { useItems, useItemProperty } from '@seedprotocol/react'
function PostRow({ seedLocalId }: { seedLocalId: string }) {
const { property } = useItemProperty({ seedLocalId, propertyName: 'title' })
return <li>{property?.value ?? 'Untitled'}</li>
}
export function PostList() {
const { items, isLoading } = useItems({ modelName: 'Post' })
if (isLoading) return <p>Loading posts…</p>
if (items.length === 0) return <p>No posts yet.</p>
return (
<ul>
{items.map((item) => (
<PostRow key={item.seedLocalId} seedLocalId={item.seedLocalId} />
))}
</ul>
)
}seedLocalId is the item's ID in the local database. Once an item is published it also has a seedUid, its EAS attestation UID.
Render them
Put both components anywhere under SeedClientGate:
import { NewPost } from './NewPost'
import { PostList } from './PostList'
export function PostsPanel() {
return (
<section>
<NewPost />
<PostList />
</section>
)
}Run the app, type a title and click Add post. The post appears in the list straight away, because useItems runs a live query on the local database. Refresh the page and it's still there.
Without React
With the client started by client.init (see Add Seed to your app), Item.create and Item.all do the same work:
import { Item } from '@seedprotocol/sdk'
const post = await Item.create({ modelName: 'Post', title: 'Hello, Seed' })
const posts = await Item.all('Post', false, { waitForReady: true })
console.log(posts.length, post.seedLocalId)Item.all returns the items newest first, by createdAt. Unlike useItems, it reads once and doesn't update when items change. See Item.
Next steps
- Reading and writing data: updating, deleting, relations, lists and rich property types. It's a tutorial page, so its samples use the tutorial's
blogschema withPostandAuthormodels. - Publishing your first item: steps 1 to 4 set up publishing in any app, with a wallet on the OP Sepolia testnet. The later steps build on the tutorial's blog app.
- Items and Item properties: every option of the hooks used above
- Schemas, Models, Items, Properties: the data model's vocabulary on one page