- Intent: 4 个中低优先级改进 - Tasks: 5 个详细任务(Props 简化、$computed、createRenderer、watch、repeat) - Code Map: 4 个文件变更 - 验收标准: 功能/技术/文档三维度 Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
8.7 KiB
8.7 KiB
json-render Phase 2: 中低优先级改进规格
规格 ID: spec-json-render-phase2
版本: 1.0
状态: 待批准
创建日期: 2026-03-25
迭代: 2/3
Intent
本规格包含 json-render v0.15.0 迁移的中低优先级改进,这些改进不是架构迁移的核心,但能显著提升开发体验和代码质量:
- 组件 Props 类型简化 - 使用
json-shorthand-prop-types简化 Props 定义 - $computed 函数支持 - 在 JSON UI 中支持计算属性
- createRenderer API 采用 - 使用新的渲染器创建 API
- watch/repeat 属性支持 - 添加响应式和重复渲染能力
Approach
阶段 1: Props 类型简化
使用 @json-render/shorthand-prop-types 简化组件 Props 定义:
// 简化前
import { z } from 'zod';
const CardSchema = z.object({
title: z.string().optional(),
description: z.string().optional(),
children: z.array(z.any()).optional(),
});
type CardProps = z.infer<typeof CardSchema>;
// 简化后
import { s } from '@json-render/shorthand-prop-types';
const CardSchema = {
title: s.string.optional,
description: s.string.optional,
children: s.array.optional,
};
阶段 2: $computed 函数集成
在 JSONUIProvider 中添加 functions prop,支持计算属性:
<JSONUIProvider
functions={{
formatDate: (date: string) => new Date(date).toLocaleDateString('zh-CN'),
formatCurrency: (amount: number) => `¥${amount.toFixed(2)}`,
pluralize: (count: number, singular: string, plural: string) =>
count === 1 ? singular : plural,
}}
>
<JsonRenderer spec={spec} />
</JSONUIProvider>
阶段 3: createRenderer 迁移
使用 createRenderer API 简化渲染器创建:
// 简化前
const JsonRenderer = ({ spec }: { spec: JsonSpec }) => {
return (
<JSONUIProvider>
<ComponentRenderer spec={spec} />
</JSONUIProvider>
);
};
// 简化后
import { createRenderer } from '@json-render/core';
const JsonRenderer = createRenderer();
阶段 4: watch/repeat 支持
添加响应式和重复渲染能力:
// watch - 响应式更新
const specWithWatch = {
type: 'text',
content: '$formatDate(data.createdAt)',
watch: ['data.createdAt'], // 依赖变化时重新渲染
};
// repeat - 列表渲染
const specWithRepeat = {
type: 'stack',
repeat: {
items: '$data.items', // 数据源
template: { // 每项的模板
type: 'card',
title: '$item.name',
},
},
};
Tasks
Task 1: 简化组件 Props 类型定义
文件: frontend-v2/lib/json-render-catalog.tsx
操作:
- 移除
z.infer类型推导 - 使用简化类型直接定义 Props
- 保持 Zod Schema 用于运行时验证
代码变更:
// 当前代码
import { z } from 'zod';
export const CardSchema = z.object({
title: z.string().optional(),
description: z.string().optional(),
children: z.array(z.any()).optional(),
});
export type CardProps = z.infer<typeof CardSchema>;
// 简化后
export const CardSchema = z.object({
title: z.string().optional(),
description: z.string().optional(),
children: z.array(z.any()).optional(),
});
export type JsonRenderProps = {
title?: string;
description?: string;
children?: JsonSpec[];
};
验收标准:
- 组件 Props 类型定义简洁
- 运行时验证仍然有效
- TypeScript 类型检查通过
Task 2: 在 JSONUIProvider 中添加 functions prop
文件: frontend-v2/components/JsonRenderer.tsx
操作:
- 添加
functionsprop 到JSONUIProvider - 将 functions 传递给
ComponentRenderer - 在表达式求值时支持函数调用
代码变更:
// JsonRenderer.tsx
interface JSONUIProviderProps {
children: React.ReactNode;
functions?: Record<string, (...args: any[]) => any>;
}
export const JSONUIProvider: React.FC<JSONUIProviderProps> = ({
children,
functions = {},
}) => {
const contextValue = useMemo(
() => ({ functions }),
[functions]
);
return (
<JsonRenderContext.Provider value={contextValue}>
{children}
</JsonRenderContext.Provider>
);
};
验收标准:
- 可以在 spec 中使用
$formatDate()等函数 - 函数调用正确传递参数
- 函数执行错误有友好提示
Task 3: 迁移到 createRenderer API
文件: frontend-v2/components/JsonRenderer.tsx
操作:
- 使用
createRenderer替换手动 Provider 包装 - 简化组件结构
- 保持向后兼容
代码变更:
// 迁移前
export const JsonRenderer: React.FC<JsonRendererProps> = ({ spec }) => {
return (
<JSONUIProvider>
<ComponentRenderer spec={spec} />
</JSONUIProvider>
);
};
// 迁移后
import { createRenderer } from '@json-render/core';
export const JsonRenderer = createRenderer();
验收标准:
- 代码量减少
- 功能保持不变
- 现有组件正常工作
Task 4: 添加 watch 属性支持
文件: frontend-v2/lib/json-render-catalog.tsx
操作:
- 扩展 JsonSchema 类型,添加
watch属性 - 在
ComponentRenderer中实现 watch 逻辑 - 使用 React hooks 监听依赖变化
代码变更:
// 扩展类型
export interface WatchableSchema extends JsonSchema {
watch?: string[]; // 依赖路径
}
// ComponentRenderer 中的实现
export const ComponentRenderer: React.FC<RendererProps> = ({ spec }) => {
const watchDeps = spec.watch || [];
const [data, setData] = useState(contextData);
useEffect(() => {
// 监听依赖变化
const unsubscribe = watchDependencies(watchDeps, (newData) => {
setData(newData);
});
return unsubscribe;
}, [watchDeps]);
return <ConcreteComponent {...spec} data={data} />;
};
验收标准:
- watch 属性正确触发重新渲染
- 依赖路径支持嵌套访问
- 无内存泄漏
Task 5: 添加 repeat 属性支持
文件: frontend-v2/lib/json-render-catalog.tsx
操作:
- 扩展 JsonSchema 类型,添加
repeat属性 - 在
ComponentRenderer中实现 repeat 逻辑 - 支持动态列表渲染
代码变更:
// 扩展类型
export interface RepeatableSchema extends JsonSchema {
repeat?: {
items: string | any[]; // 数据源路径或数组
template: JsonSchema; // 每项的模板
key?: string; // 唯一键字段
};
}
// ComponentRenderer 中的实现
export const ComponentRenderer: React.FC<RendererProps> = ({ spec, data }) => {
if (spec.repeat) {
const items = typeof spec.repeat.items === 'string'
? get(data, spec.repeat.items)
: spec.repeat.items;
return (
<>
{items.map((item, index) => (
<JsonRenderer
key={spec.repeat.key ? item[spec.repeat.key] : index}
spec={spec.repeat.template}
data={{ ...data, item }}
/>
))}
</>
);
}
return <ConcreteComponent {...spec} />;
};
验收标准:
- repeat 属性正确渲染列表
- 支持嵌套路径访问
- key 属性正确工作
Code Map
| 文件 | 变更类型 | 描述 |
|---|---|---|
frontend-v2/lib/json-render-catalog.tsx |
修改 | 简化 Props 类型,添加 watch/repeat 支持 |
frontend-v2/lib/json-render-registry.tsx |
修改 | 更新组件注册方式 |
frontend-v2/components/JsonRenderer.tsx |
修改 | 添加 functions prop,迁移到 createRenderer |
frontend-v2/app/page.tsx |
修改 | 更新使用方式 |
验收标准
功能验收
- 所有组件使用简化的 Props 类型
- $computed 函数在 spec 中可用
- watch 属性正确触发重新渲染
- repeat 属性正确渲染列表
技术验收
- TypeScript 类型检查通过
- 运行时验证仍然有效
- 性能无明显下降
- 无内存泄漏
文档验收
- 更新 JSON_RENDER_USAGE.md
- 添加 $computed 函数文档
- 添加 watch/repeat 使用示例
依赖关系
本规格依赖于 Phase 1 的完成:
- Phase 1 完成后,本规格可以独立实施
- 部分功能(如 watch/repeat)可能需要 Phase 1 的基础设施
时间估算
| Task | 预估时间 |
|---|---|
| Task 1: Props 简化 | 2 小时 |
| Task 2: $computed 集成 | 3 小时 |
| Task 3: createRenderer 迁移 | 2 小时 |
| Task 4: watch 支持 | 4 小时 |
| Task 5: repeat 支持 | 4 小时 |
| 总计 | 15 小时 |
批准记录
| 字段 | 值 |
|---|---|
| 批准者 | |
| 批准日期 | |
| 批准理由 |
变更历史
| 日期 | 版本 | 变更内容 | 作者 |
|---|---|---|---|
| 2026-03-25 | 1.0 | 初始版本 | 外层 BMAD 专家 |