Agent skill
node-dev
React Flow 节点开发的完整指南。包含节点类型、Handles 连接规则、数据传递架构和开发模板。适用于创建新的自定义节点或修改现有节点。
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/node-dev
SKILL.md
React Flow 节点开发技能 v2.0
更新日期: 2026-01-23 版本: v2.0.0 定位: WinJin AIGC 项目的节点开发核心指南
节点类型分类
| 类型 | 颜色 | Handle 位置 | 示例 |
|---|---|---|---|
| 输入节点 | 蓝色 (#3b82f6) | Handle 在右侧 | APISettingsNode, CharacterLibraryNode |
| 处理节点 | 绿色 (#10b981) | Handle 在左右两侧 | VideoGenerateNode, PromptOptimizerNode |
| 输出节点 | 浅蓝 (#0ea5e9) | Handle 在左侧 | TaskResultNode, CharacterResultNode |
Handles 连接规范 ⭐ 核心
输入端口到源节点类型的映射
| 目标端口 | Handle ID | 源节点类型 | 数据传递 | 用途 |
|---|---|---|---|---|
prompt-input |
右侧 | textNode, promptOptimizerNode, narratorProcessorNode | connectedPrompt | 文本提示词输入和优化 |
character-input |
右侧 | characterLibraryNode | connectedCharacters | 角色库数据传递 |
images-input |
右侧 | referenceImageNode | connectedImages | 参考图片传递 |
api-config |
右侧 | apiSettingsNode | apiConfig | API 配置连接 |
task-input |
左侧 | videoGenerateNode, storyboardNode, characterCreateNode | taskId | 任务结果监听 |
Handle 连接验证机制
// ✅ App.jsx 中的验证逻辑
const validCharacterSourceTypes = ['characterLibraryNode'];
if (sourceNode && validCharacterSourceTypes.includes(sourceNode.type)) {
newData.connectedCharacters = sourceNode.data.connectedCharacters;
} else {
newData.connectedCharacters = undefined; // 静默失败
}
数据传递架构 ⭐ 重要
核心原则
源节点直接更新目标节点,避免依赖父组件中转
// ✅ 正确:源节点直接更新目标节点
const edges = getEdges();
const outgoingEdges = edges.filter(e => e.source === nodeId);
setNodes((nds) =>
nds.map((node) => {
// 更新自己
if (node.id === nodeId) {
return { ...node, data: { ...node.data, selectedCharacters } };
}
// 直接更新目标节点(绕过 App.jsx)
const isConnected = outgoingEdges.some(e => e.target === node.id);
if (isConnected) {
return { ...node, data: { ...node.data, connectedCharacters } };
}
return node;
})
);
事件系统(异步数据)
// 发送节点
window.dispatchEvent(new CustomEvent('video-task-created', {
detail: { sourceNodeId: nodeId, taskId: id }
}));
// 接收节点
useEffect(() => {
const handleVideoCreated = (event) => {
const { sourceNodeId, taskId } = event.detail;
if (data.connectedSourceId === sourceNodeId) {
setTaskId(taskId);
}
};
window.addEventListener('video-task-created', handleVideoCreated);
return () => window.removeEventListener('video-task-created', handleVideoCreated);
}, [data.connectedSourceId]);
节点开发最佳实践
1. useState 同步到 node.data
// 初始化
const [manualPrompt, setManualPrompt] = useState(data.manualPrompt || '');
// 同步到 node.data
useEffect(() => {
if (manualPrompt !== data.manualPrompt) {
setNodes((nds) =>
nds.map((node) =>
node.id === nodeId
? { ...node, data: { ...node.data, manualPrompt } }
: node
)
);
}
}, [manualPrompt, nodeId, setNodes, data.manualPrompt]);
2. useEffect 依赖最佳实践
// ❌ 错误:依赖 data 对象
useEffect(() => {
// ...
}, [data]); // data 每次都是新引用
// ✅ 正确:依赖具体值
useEffect(() => {
// ...
}, [data.value]); // 只依赖实际变化的值
3. 防止节点内交互触发拖动
{/* 使用 nodrag 类 */}
<textarea className="nodrag" />
<select className="nodrag">...</select>
<input className="nodrag" type="checkbox" />
<button className="nodrag">生成</button>
4. 双显示功能(角色引用)
// 创建映射
const usernameToAlias = React.useMemo(() => {
const map = {};
connectedCharacters.forEach(char => {
map[char.username] = char.alias || char.username;
});
return map;
}, [connectedCharacters]);
// 真实ID → 显示别名
const realToDisplay = (text) => {
let result = text;
Object.entries(usernameToAlias).forEach(([username, alias]) => {
const regex = new RegExp(`@${username}(?=\\s|$|@)`, 'g');
result = result.replace(regex, `@${alias}`);
});
return result;
};
// 显示别名 → 真实ID
const displayToReal = (text) => {
let result = text;
const sortedAliases = Object.entries(usernameToAlias)
.sort((a, b) => b[1].length - a[1].length);
sortedAliases.forEach(([username, alias]) => {
const regex = new RegExp(`@${alias}(?=\\s|$|@)`, 'g');
result = result.replace(regex, `@${username}`);
});
return result;
};
// Textarea 显示别名
<textarea
value={realToDisplay(manualPrompt)}
onChange={(e) => setManualPrompt(displayToReal(e.target.value))}
/>
节点开发工作流
场景1: 角色视频生成工作流
节点组合:
- CharacterLibraryNode(选择角色)
- VideoGenerateNode(输入提示词、生成视频)
- TaskResultNode(显示结果)
数据流:
CharacterLibraryNode.selectedCharacters
↓ 连接
VideoGenerateNode.connectedCharacters
↓ API 调用
TaskResultNode.taskId
↓ 轮询
TaskResultNode.videoUrl
场景2: 优化工作流
节点组合:
- TextNode(输入简单描述)
- PromptOptimizerNode(AI 优化)
- VideoGenerateNode(生成视频)
数据流:
TextNode.value
↓ 连接
PromptOptimizerNode.manualPrompt
↓ AI 优化
VideoGenerateNode.manualPrompt
↓ API 调用
TaskResultNode.taskId
场景3: 故事板工作流
节点组合:
- TextNode(输入多个镜头描述)
- StoryboardNode(拼接故事板格式)
- TaskResultNode(显示结果)
数据流:
TextNode.value × N
↓ 连接
StoryboardNode.shots
↓ API 调用(故事板专用端点)
TaskResultNode.taskId
详细文档
references/ 目录
- 节点架构 - 完整的架构模式
- Handle 连接 - 连接规范详解
- 节点模板 - 代码模板库
- 节点功能参考手册 - 所有节点功能文档
相关文档
- 错误模式参考 - 节点相关错误
- 开发交接书 - 版本记录
快速开始
新手入门(15分钟)
- 阅读 节点架构 - 理解节点架构
- 阅读 Handle 连接 - 学习连接规范
- 浏览 节点模板 - 使用代码模板
进阶开发者(20分钟)
- 深入理解 Handle 连接 - 掌握连接验证
- 精读 节点功能参考手册 - 熟悉所有节点
- 应用到实际开发 - 创建自定义节点
常见问题
Q: 如何防止节点间数据传递丢失?
A: 使用源节点直接更新目标节点模式,绕过 App.jsx 的中转
Q: useEffect 无限循环怎么办?
A:
- 移除
data从依赖数组 - 使用
useRef存储回调 - 只依赖实际变化的值
Q: 如何实现双显示功能?
A: 参考上面的"双显示功能"示例代码
维护者: WinJin AIGC Team 最后更新: 2026-01-23 版本: v2.0.0
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?