react

react

熱門

json-render 的 React 渲染器,可將 JSON 規格轉換為 React 元件。適用於使用 @json-render/react、從 JSON 建構 React UI、建立元件目錄或渲染 AI 生成的規格時。

1.6萬星標
844分支
更新於 2026/7/8
SKILL.md
唯讀
名稱
react
描述

json-render 的 React 渲染器,可將 JSON 規格轉換為 React 元件。適用於使用 @json-render/react、從 JSON 建構 React UI、建立元件目錄或渲染 AI 生成的規格時。

@json-render/react

React 渲染器,可將 JSON 規格轉換為 React 元件樹。

快速開始

import { defineRegistry, Renderer } from "@json-render/react";
import { catalog } from "./catalog";

const { registry } = defineRegistry(catalog, {
  components: {
    Card: ({ props, children }) => <div>{props.title}{children}</div>,
  },
});

function App({ spec }) {
  return <Renderer spec={spec} registry={registry} />;
}

建立目錄

import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/react/schema";
import { defineRegistry } from "@json-render/react";
import { z } from "zod";

// 建立帶有 props 結構的目錄
export const catalog = defineCatalog(schema, {
  components: {
    Button: {
      props: z.object({
        label: z.string(),
        variant: z.enum(["primary", "secondary"]).nullable(),
      }),
      description: "可點擊的按鈕",
    },
    Card: {
      props: z.object({ title: z.string() }),
      description: "帶有標題的卡片容器",
    },
  },
});

// 定義具有型別安全 props 的元件實作
const { registry } = defineRegistry(catalog, {
  components: {
    Button: ({ props }) => (
      <button className={props.variant}>{props.label}</button>
    ),
    Card: ({ props, children }) => (
      <div className="card">
        <h2>{props.title}</h2>
        {children}
      </div>
    ),
  },
});

規格結構(元素樹)

React 結構使用元素樹格式:

{
  "root": {
    "type": "Card",
    "props": { "title": "Hello" },
    "children": [
      { "type": "Button", "props": { "label": "Click me" } }
    ]
  }
}

可見性條件

在元素上使用 visible 根據狀態顯示/隱藏。新語法:{ "$state": "/path" }{ "$state": "/path", "eq": value }{ "$state": "/path", "not": true }{ "$and": [cond1, cond2] } 用於 AND、{ "$or": [cond1, cond2] } 用於 OR。輔助函式:visibility.when("/path")visibility.unless("/path")visibility.eq("/path", val)visibility.and(cond1, cond2)visibility.or(cond1, cond2)

提供者

提供者 用途
StateProvider 在元件間共享狀態(JSON Pointer 路徑)。可接受選用的 store prop 以使用受控模式。
ActionProvider 處理透過事件系統觸發的動作
VisibilityProvider 啟用基於狀態的條件渲染
ValidationProvider 表單欄位驗證

外部 Store(受控模式)

StateStore 傳遞給 StateProvider(或 JSONUIProvider / createRenderer)以使用外部狀態管理(Redux、Zustand、XState 等):

import { createStateStore, type StateStore } from "@json-render/react";

const store = createStateStore({ count: 0 });

<StateProvider store={store}>{children}</StateProvider>

// 從任何地方變更 — React 會自動重新渲染:
store.set("/count", 1);

當提供了 store 時,initialStateonStateChange 會被忽略。

動態 Prop 表達式

任何 prop 值都可以是資料驅動的表達式,在元件接收 props 之前由渲染器解析:

  • { "$state": "/state/key" } - 從狀態模型讀取(單向讀取)
  • { "$bindState": "/path" } - 雙向綁定:從狀態讀取並允許寫回。用於表單元件的自然值 prop(value、checked、pressed 等)。
  • { "$bindItem": "field" } - 雙向綁定到重複項目的欄位。在重複範圍內使用。
  • 過濾列表:在同一個容器上使用 repeat 加上 $item 可見條件,僅渲染符合條件的項目:{ "repeat": { "statePath": "/tasks", "key": "id" }, "visible": { "$item": "status", "eq": "todo" }, "children": ["task-card"] }。AND 組合的 $state 條件控制容器外殼;$item/$index 條件過濾項目。
  • { "$cond": <condition>, "$then": <value>, "$else": <value> } - 條件值
  • { "$template": "Hello, ${/name}!" } - 將狀態值插入字串
  • { "$computed": "fn", "args": { ... } } - 使用解析後的參數呼叫已註冊的函式
{
  "type": "Input",
  "props": {
    "value": { "$bindState": "/form/email" },
    "placeholder": "Email"
  }
}

元件不使用 statePath prop 進行雙向綁定。請改用 { "$bindState": "/path" } 放在自然值 prop 上。

元件接收已解析的 props。對於雙向綁定的 props,請使用 useBoundProp hook 搭配渲染器提供的 bindings 映射。

透過 JSONUIProvidercreateRendererfunctions prop 註冊 $computed 函式:

<JSONUIProvider
  functions={{ fullName: (args) => `${args.first} ${args.last}` }}
>

事件系統

元件使用 emit 觸發命名事件,或使用 on() 取得帶有元資料的事件控制代碼。元素的 on 欄位將事件映射到動作綁定:

// 簡單事件觸發
Button: ({ props, emit }) => (
  <button onClick={() => emit("press")}>{props.label}</button>
),

// 帶有元資料的事件控制代碼(例如 preventDefault)
Link: ({ props, on }) => {
  const click = on("click");
  return (
    <a href={props.href} onClick={(e) => {
      if (click.shouldPreventDefault) e.preventDefault();
      click.emit();
    }}>{props.label}</a>
  );
},
{
  "type": "Button",
  "props": { "label": "Submit" },
  "on": { "press": { "action": "submit" } }
}

EventHandleon() 回傳,包含:emit()shouldPreventDefault(布林值)和 bound(布林值)。

狀態監聽器

元素可以宣告 watch 欄位(頂層,與 type/props/children 同層級),在狀態值變更時觸發動作:

{
  "type": "Select",
  "props": { "value": { "$bindState": "/form/country" }, "options": ["US", "Canada"] },
  "watch": { "/form/country": { "action": "loadCities" } },
  "children": []
}

內建動作

setStatepushStateremoveStatevalidateForm 動作內建於 React 結構中,並由 ActionProvider 自動處理。它們會自動注入到 AI 提示中,無需在目錄的 actions 中宣告:

{ "action": "setState", "params": { "statePath": "/activeTab", "value": "home" } }
{ "action": "pushState", "params": { "statePath": "/items", "value": { "text": "New" } } }
{ "action": "removeState", "params": { "statePath": "/items", "index": 0 } }
{ "action": "validateForm", "params": { "statePath": "/formResult" } }

validateForm 會驗證所有已註冊的欄位,並將 { valid, errors } 寫入狀態。

注意:動作參數中的 statePath(例如 setState.statePath)指定變更路徑。元件 props 中的雙向綁定使用 { "$bindState": "/path" } 放在值 prop 上,而不是 statePath

useBoundProp

對於需要雙向綁定的表單元件,請使用 useBoundProp 搭配渲染器提供的 bindings 映射,當 prop 使用 { "$bindState": "/path" }{ "$bindItem": "field" } 時:

import { useBoundProp } from "@json-render/react";

Input: ({ element, bindings }) => {
  const [value, setValue] = useBoundProp<string>(
    element.props.value,
    bindings?.value
  );
  return (
    <input
      value={value ?? ""}
      onChange={(e) => setValue(e.target.value)}
    />
  );
},

useBoundProp(propValue, bindingPath) 回傳 [value, setValue]value 是解析後的 prop;setValue 會寫回綁定的狀態路徑(若未綁定則無作用)。

BaseComponentProps

用於建立不綁定特定目錄的可重用元件庫(例如 @json-render/shadcn):

import type { BaseComponentProps } from "@json-render/react";

const Card = ({ props, children }: BaseComponentProps<{ title?: string }>) => (
  <div>{props.title}{children}</div>
);

defineRegistry

defineRegistry 僅在目錄宣告了動作時才需要 actions 欄位。目錄中若為 actions: {} 則可省略。

主要匯出

匯出名稱 用途
defineRegistry 從目錄建立型別安全的元件註冊表
Renderer 使用註冊表渲染規格
schema 元素樹結構(包含內建狀態動作:setState、pushState、removeState、validateForm)
useStateStore 存取狀態上下文
useStateValue 從狀態取得單一值
useBoundProp 用於 $bindState/$bindItem 表達式的雙向綁定
useActions 存取動作上下文
useAction 取得單一動作觸發函式
useOptionalValidation useValidation 的非拋出變體(若無提供者則回傳 null)
useUIStream 從 API 端點串流規格
createStateStore 建立與框架無關的記憶體 StateStore
StateStore 用於插入外部狀態管理的介面
BaseComponentProps 與目錄無關的基礎型別,用於可重用元件庫
EventHandle 事件控制代碼型別(emitshouldPreventDefaultbound
ComponentContext 型別化的元件上下文(感知目錄)