Skip to content
LogoLogo

Content

The client holds every content record in one index, keyed by the id. The hooks on this page read that index.

The content record

interface Content {
  id: string
  contentModelKey?: string | null
  data: Record<string, unknown>
}
PropertyTypeDescription
idstringThe content entry id.
contentModelKeystring | nullThe Key of the Model that the entry belongs to.
dataRecord<string, unknown>The field values, keyed by the field key from the schema.

The client registers the content array and the references array of the experience content response into the same index. Your code can therefore read a referenced entry by its own id.

Read the content of a step

useStepContent() in React, and getStepContent() in Svelte, give the data of the entry that the current step points at.

import { useStepContent } from '@picked/react/hooks'
 
export function Hero() {
  const content = useStepContent()
 
  return <h1>{String(content?.headline ?? '')}</h1>
}

useStepContent() returns the data, and React re-renders the component when the data changes. getStepContent() returns a store, which you read with the $ prefix.

Read the record of a step

useStepLayoutContent() in React, and getStepLayoutContent() in Svelte, give the whole record, which includes contentModelKey. They read the same record as useStepContent(), both inside a step and in an experience that <ExperienceSlot> renders. isContentOfModel narrows the record to one model. See Type generation.

import { isContentOfModel } from '@picked/client'
import { useStepLayoutContent } from '@picked/react/hooks'
 
export function Page() {
  const record = useStepLayoutContent()
 
  if (record && isContentOfModel(record, 'landing-page')) {
    return <h1>{String(record.data.headline ?? '')}</h1>
  }
 
  return null
}

Read a record by id

useContent(id) and getContent(id) return a store of one record. The store holds null until the client registers that record.

import { useContent, useStoreGlobal } from '@picked/react/hooks'
 
export function Banner() {
  const banner = useStoreGlobal(useContent('entry_42'))
 
  return <h1>{String(banner?.data.headline ?? '')}</h1>
}

Resolve a reference field

A Reference field holds a pointer, and not the record. useReference() and getReference() resolve the pointer against the index.

import { useReference, useStepContent, useStoreGlobal } from '@picked/react/hooks'
 
export function ProductCategory() {
  const content = useStepContent()
  const category = useStoreGlobal(useReference(content?.category))
 
  return <span>{String(category?.data.name ?? '')}</span>
}

For a repeatable Reference field, use useReferences() and getReferences(). They give a list in field order.

import { useReferences, useStepContent, useStoreGlobal } from '@picked/react/hooks'
 
export function ProductCategories() {
  const content = useStepContent()
  const categories = useStoreGlobal(useReferences(content?.categories))
 
  return (
    <ul>
      {categories.map((category) => (
        <li key={category.id}>{String(category.data.name ?? '')}</li>
      ))}
    </ul>
  )
}

The list holds no empty places. A pointer that Picked cannot resolve is absent from the list, so each item is a record.

Reference hooks

HookReturnsWhen the target is absent
useReference(value)Store<Content | null>null
useReferences(value)Store<Content[]>The item is absent from the list.
getReference(value)Store<Content | null>null
getReferences(value)Store<Content[]>The item is absent from the list.

Each one accepts the raw field value, or a store of it. A single value that goes to useReferences() or getReferences() gives a list of one.

A target is absent for three reasons. Somebody deleted the entry, the entry belongs to another workspace, or the chain of references is deeper than the limit. See About content references.

Read a pointer directly

@picked/client gives you the readers behind the hooks, for the code that runs outside React and Svelte.

ExportReturnsDescription
isContentReference(value)booleanWhether the value is a pointer.
readReferenceId(value)string | nullThe target id of a single pointer.
readReferenceIds(value)string[]Every target id, for a repeatable field.
deriveReference(contents, value)Store<Content | null>The store behind useReference and getReference.
deriveReferences(contents, value)Store<Content[]>The store behind useReferences and getReferences.
import { createClient, readReferenceIds } from 'picked'
 
const client = createClient({ projectId: 'proj_123' })
const content = client.contents.getById('entry_789').getState()
const categoryIds = readReferenceIds(content?.data.categories)