jazz-ui-development

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Jazz UI Development

Jazz UI 开发

When to Use This Skill

何时使用此技能

  • Building user interfaces that display or interact with Jazz data
  • Setting up authentication providers and contexts
  • Debugging reactivity, data loading, or sync issues in the UI
  • Optimizing performance of data subscriptions
  • Handling media (images, files) in the UI
  • 构建展示Jazz数据或与Jazz数据交互的用户界面
  • 配置身份认证providers和contexts
  • 调试UI中的响应性、数据加载或同步问题
  • 优化数据订阅的性能
  • 在UI中处理媒体资源(图片、文件)

Do NOT Use This Skill For

请勿将此技能用于

  • Defining data schemas (use
    jazz-schema-design
    )
  • Complex permission logic or sharing workflows (use
    jazz-permissions-security
    )
  • Testing questions (use
    jazz-testing
    )
  • 定义数据schemas(请使用
    jazz-schema-design
  • 复杂权限逻辑或共享工作流(请使用
    jazz-permissions-security
  • 测试相关问题(请使用
    jazz-testing

Key Heuristic for Agents

给Agent的关键判断规则

Use this skill when the user asks about rendering data, handling user input, managing authentication state, or framework-specific integration (React, Svelte, etc.). If the issue is "data not appearing" but permissions are correct, look here for loading and subscription patterns.
当用户询问渲染数据、处理用户输入、管理身份认证状态或特定框架集成(React、Svelte等)相关问题时使用此技能。如果出现「数据不展示」但权限校验正常的问题,可在此查找加载和订阅模式相关的解决方案。

Framework Guides

框架指南

Select the guide for your specific framework:
  • React: React Reference
  • React Native (Bare): As well as the React guide, also see React Native Reference
  • React Native (Expo): As well as the React guide, also seeReact Native (Expo) Reference
  • Svelte: Svelte Reference
  • Vanilla JS: Vanilla JS Reference
选择适配你所用框架的指南:
  • React: React 参考文档
    • React Native (裸项目):除React指南外,还可参考 React Native 参考文档
    • React Native (Expo):除React指南外,还可参考 React Native (Expo) 参考文档
  • Svelte: Svelte 参考文档
  • Vanilla JS: 原生JS 参考文档

Universal CoValue API

通用CoValue API

These APIs are available on all CoValue instances, regardless of the framework.
以下API在所有CoValue实例上都可用,与所用框架无关。

Core Properties

核心属性

All CoValues (CoMaps, CoLists, etc.) have these properties directly on the instance:
  • $isLoaded
    (
    boolean
    ): Returns
    true
    if the CoValue is fully loaded and ready to read.
  • .toJSON()
    : Returns a plain JavaScript object representation of the CoValue. Use this for debugging only, not for rendering.
所有CoValues(CoMaps、CoLists等)的实例都直接具备以下属性:
  • $isLoaded
    (
    boolean
    ): 当CoValue完全加载完毕可读取时返回
    true
  • .toJSON()
    : 返回CoValue的普通JavaScript对象表示形式。仅用于调试,不要用于渲染逻辑。

The
.$jazz
Namespace

.$jazz
命名空间

Every CoValue instance has a
.$jazz
property containing metadata and utility methods.
每个CoValue实例都有一个
.$jazz
属性,包含元数据和工具方法。

Metadata

元数据

  • .$jazz.id
    (
    ID<CoValue>
    ): The globally unique ID of the CoValue (e.g.,
    co_zXy...
    ).
  • .$jazz.owner
    (
    Group
    ): The Group that owns this CoValue. Access control is determined by membership in this group.
  • .$jazz.createdAt
    (
    number
    ): Creation timestamp (ms since epoch).
  • .$jazz.createdBy
    (
    ID<Account> | undefined
    ): ID of the creating account.
  • .$jazz.lastUpdatedAt
    (
    number
    ): Last update timestamp (ms since epoch).
  • .$jazz.id
    (
    ID<CoValue>
    ): CoValue的全局唯一ID(例如
    co_zXy...
  • .$jazz.owner
    (
    Group
    ): 拥有此CoValue的Group。访问权限由该组的成员资格决定
  • .$jazz.createdAt
    (
    number
    ): 创建时间戳(纪元以来的毫秒数)
  • .$jazz.createdBy
    (
    ID<Account> | undefined
    ): 创建账号的ID
  • .$jazz.lastUpdatedAt
    (
    number
    ): 最后更新时间戳(纪元以来的毫秒数)

Loading & Inspection

加载与检查

  • .$jazz.loadingState
    (
    "loading" | "loaded" | "unavailable" | "unauthorized"
    ): The current loading state.
  • .$jazz.ensureLoaded({ resolve: { ... } })
    : Waits for nested references to load. Returns a promise with a new instance where requested fields are guaranteed available.
ts
const detailedPost = await post.$jazz.ensureLoaded({
  resolve: {
    comments: {
      $each: {
        author: true 
      }
    }
  }
});
  • .$jazz.refs
    (CoMap/CoRecord only): Access nested CoValues as references (with IDs) without loading them.
  • .$jazz.has(key)
    (CoMap/CoRecord only): Checks if a key exists.
  • .$jazz.loadingState
    (
    "loading" | "loaded" | "unavailable" | "unauthorized"
    ): 当前加载状态
  • .$jazz.ensureLoaded({ resolve: { ... } })
    : 等待嵌套引用加载完成。返回一个带实例的Promise,其中请求的字段保证可用。
ts
const detailedPost = await post.$jazz.ensureLoaded({
  resolve: {
    comments: {
      $each: {
        author: true 
      }
    }
  }
});
  • .$jazz.refs
    (仅CoMap/CoRecord支持): 无需加载即可作为引用(带ID)访问嵌套CoValues
  • .$jazz.has(key)
    (仅CoMap/CoRecord支持): 检查某个key是否存在

Subscription & Sync

订阅与同步

  • .$jazz.subscribe(callback)
    : Manually subscribe to changes. Returns an unsubscribe function. Prefer framework-specific hooks (e.g.,
    useCoState
    ) over this.
  • .$jazz.waitForSync()
    : Promise that resolves when changes are synced to peers. Useful for critical saves or logout flows.
  • .$jazz.subscribe(callback)
    : 手动订阅变更,返回取消订阅的函数。优先使用框架专属hooks(例如
    useCoState
    )而非此方法
  • .$jazz.waitForSync()
    : 变更同步到对等节点后resolve的Promise,适用于关键保存或登出流程

Version Control

版本控制

  • .$jazz.isBranched
    (
    boolean
    ): Whether the CoValue is currently in a local branch.
  • .$jazz.branchName
    (
    string
    ): The name of the current branch.
  • .$jazz.unstable_merge()
    : Merges a branch back into the main history.
  • .$jazz.isBranched
    (
    boolean
    ): CoValue当前是否处于本地分支
  • .$jazz.branchName
    (
    string
    ): 当前分支的名称
  • .$jazz.unstable_merge()
    : 将分支合并回主历史记录

Working with Data Types

数据类型使用指南

CoMap / CoRecord

CoMap / CoRecord

  • Read: Access properties like a standard JS object (e.g.,
    user.name
    ).
  • Write:
    • .$jazz.set(key, value)
    • .$jazz.delete(key)
    • .$jazz.applyDiff(diff)
  • 读取: 像标准JS对象一样访问属性(例如
    user.name
  • 写入:
    • .$jazz.set(key, value)
    • .$jazz.delete(key)
    • .$jazz.applyDiff(diff)

CoList

CoList

  • Read: Access by index (
    list[0]
    ), iterate (
    map
    ,
    forEach
    ).
  • Write:
    • .$jazz.push(item)
    • .$jazz.unshift(item)
    • .$jazz.splice(...)
    • .$jazz.remove(index or predicate)
  • 读取: 按下标访问(
    list[0]
    )、迭代(
    map
    forEach
  • 写入:
    • .$jazz.push(item)
    • .$jazz.unshift(item)
    • .$jazz.splice(...)
    • .$jazz.remove(index or predicate)

CoText (CoPlainText / CoRichText)

CoText (CoPlainText / CoRichText)

  • Read:
    toString()
    or use directly in template.
  • Write:
    • insertAfter(index, text)
    • deleteRange({ from, to })
    • .$jazz.applyDiff(newText)
  • 读取: 调用
    toString()
    或直接在模板中使用
  • 写入:
    • insertAfter(index, text)
    • deleteRange({ from, to })
    • .$jazz.applyDiff(newText)

CoFeed

CoFeed

  • Read: Iterate over
    feed.all
    (returns per-session feeds).
  • Write:
    .$jazz.push(item)
    (Append-only).
ts
// Subscribing to all entries across all accounts
const allEntries = Object.values(feed.perAccount).flatMap(accountFeed => Array.from(accountFeed.all));

// Pushing a new entry
feed.$jazz.push({ message: "Hello", timestamp: Date.now() });
  • 读取: 遍历
    feed.all
    (返回按会话划分的feed)
  • 写入:
    .$jazz.push(item)
    (仅支持追加)
ts
// 订阅所有账号的所有条目
const allEntries = Object.values(feed.perAccount).flatMap(accountFeed => Array.from(accountFeed.all));

// 推送新条目
feed.$jazz.push({ message: "Hello", timestamp: Date.now() });

DiscriminatedUnion

DiscriminatedUnion

  • Read: Check the discriminator property (e.g.
    type
    ) to narrow the type.
  • Write: Overwrite the property with a new object of the desired variant.
ts
const list = co.list(MyUnion);
const item = list[0];

if (item.type === "text") {
  console.log(item.value); // item is narrowed to TextVariant
} else if (item.type === "image") {
  console.log(item.image.$jazz.id); // item is narrowed to ImageVariant
}
  • 读取: 检查判别属性(例如
    type
    )来收窄类型
  • 写入: 用目标变体的新对象覆盖对应属性
ts
const list = co.list(MyUnion);
const item = list[0];

if (item.type === "text") {
  console.log(item.value); // item被收窄为TextVariant类型
} else if (item.type === "image") {
  console.log(item.image.$jazz.id); // item被收窄为ImageVariant类型
}

FileStream

FileStream

  • Read: Use
    toBlob()
    or consume chunks.
  • Write: Use
    createFromBlob(blobOrFile)
    or
    start(metadata) -> push(chunk) -> end()
    .
  • 读取: 使用
    toBlob()
    或逐块消费
  • 写入: 使用
    createFromBlob(blobOrFile)
    或按
    start(metadata) -> push(chunk) -> end()
    流程操作

ImageDefinition

ImageDefinition

  • Read: Use
    <Image>
    component (framework specific) or
    loadImageBySize
    .
  • Write: use the
    createImage
    function from
    jazz-tools/media
tsx
<Image imageId={productImage.$jazz.id} width={300} />
  • 读取: 使用
    <Image>
    组件(框架专属)或
    loadImageBySize
  • 写入: 使用
    jazz-tools/media
    提供的
    createImage
    函数
tsx
<Image imageId={productImage.$jazz.id} width={300} />

Troubleshooting

故障排查

"Data not appearing" or "Value is undefined"

"数据不展示"或"值为undefined"

  1. Check
    $isLoaded
    : Ensure you are checking
    if (coValue.$isLoaded)
    before rendering.
  2. Deep Loading: If nested data is missing, use
    resolve
    in your hook (e.g.
    useCoState(..., { resolve: { items: true } })
    ).
  3. Provider Check: Ensure the component is wrapped in the appropriate
    <JazzProvider />
    .
  1. 检查
    $isLoaded
    : 确保渲染前已判断
    if (coValue.$isLoaded)
  2. 深层加载: 如果嵌套数据缺失,在hook中使用
    resolve
    配置(例如
    useCoState(..., { resolve: { items: true } })
  3. Provider检查: 确保组件被正确包裹在对应的
    <JazzProvider />

"Infinite re-render loops"

"无限重渲染循环"

  1. Selector Stability: Ensure your
    select
    function in
    useCoState
    is stable or returns stable references.
  2. Expensive Selectors: Move computations to
    useMemo
    instead of doing them inside the
    select
    function.
  3. Equality Function: Use
    equalityFn
    to prevent unnecessary updates if the selected data hasn't changed semantically.
  1. 选择器稳定性: 确保
    useCoState
    中的
    select
    函数是稳定的,或者返回稳定的引用
  2. 昂贵选择器: 将计算逻辑移到
    useMemo
    中,不要在
    select
    函数内部执行
  3. 相等性判断函数: 如果选中数据语义上没有变化,可使用
    equalityFn
    避免不必要的更新

"Reactivity not triggering"

"响应性不触发"

  1. Direct Mutations: Ensure you are using
    .$jazz.set()
    or
    .$jazz.push()
    instead of direct property assignment (e.g.
    obj.key = val
    won't sync).
  2. Deep Updates: Remember that updating a nested scalar doesn't trigger a change in the parent CoValue unless that parent property is replaced.
  1. 直接修改: 确保你使用的是
    .$jazz.set()
    .$jazz.push()
    ,而非直接赋值属性(例如
    obj.key = val
    不会触发同步)
  2. 深层更新: 注意更新嵌套的标量值不会触发父级CoValue的变更,除非父级属性被整体替换