React flow node graph architect
Skill findscripter/everything-skills/02-engineering/react-flow-node-graph-architect
当用 ReactFlow 构建可交互节点图(树形导航/大数据量/复杂状态)时使用;做出层级展开、性能优化与状态管理(含撤销重做、自动布局、聚焦/搜索)的生产级实现;不适用于静态流程图、纯 SVG 绘图或非 ReactFlow 图库。触发词:ReactFlow、节点图、自动布局From its SKILL.md
npx -y skills add findscripter/everything-skills --skill react-flow-node-graph-architectAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
8.2 KB, ~2.4k tokens by cl100k_base, as published. Nobody here has run it
何时使用
当你要用 ReactFlow 搭建生产级的可交互节点图时使用本技能,典型场景:
- 需要层级树形导航(父子节点、可展开/折叠)。
- 数据量大(数百至上千节点),需要增量渲染与 memo 化控制性能。
- 需要复杂状态管理:选中、展开集合、撤销/重做、持久化、自动保存。
- 需要 Dagre 自动布局、聚焦模式、节点搜索定位等进阶交互。
不该用的边界:
- 只是画静态流程图/示意图,用 Mermaid、PlantUML 或纯 SVG 更省事。
- 使用的不是 ReactFlow(如 D3、Cytoscape、X6、vis-network),模式不直接通用。
- 节点数极小且无交互需求,直接用最简
<ReactFlow>即可,无需本技能的优化套路。
步骤 / 指令
- 起步:装
reactflow,渲染最小图验证依赖与样式正常。 - 定义类型:先用 TypeScript 给节点
data建模(level、hasChildren、isExpanded、category等),类型先行避免后期返工。 - 构建可见集:树形场景用
expandedIds: Set<string>递归从根节点计算可见节点/边,而非渲染全量。 - 接状态管理:用
useReducer统一处理选中、展开、更新、撤销/重做;展开/选中走 action,保证可回溯。 - 加性能层:节点组件
React.memo+ 自定义比较函数;useMemo缓存样式化边;Map做 O(1) 查找。 - 接自动布局:用 Dagre 计算坐标,并
debounce(约 150ms)+ 缓存结果,避免高频交互抖动。 - 加进阶交互(按需):聚焦模式隔离选中节点及其直接连接;搜索后展开父链并
fitView定位。 - 校验性能:节点数 > 500 提示虚拟化;单帧渲染估算 > 16ms(掉 60fps)则优化。
示例
最小可交互图:
import ReactFlow, { Node, Edge } from "reactflow";
const nodes: Node[] = [
{ id: "1", position: { x: 0, y: 0 }, data: { label: "Node 1" } },
{ id: "2", position: { x: 100, y: 100 }, data: { label: "Node 2" } },
];
const edges: Edge[] = [{ id: "e1-2", source: "1", target: "2" }];
export default function Graph() {
return <ReactFlow nodes={nodes} edges={edges} />;
}
树形可见集递归(只渲染展开路径):
const buildVisibleNodes = useCallback(
(allNodes: TreeNode[], expandedIds: Set<string>) => {
const visibleNodes = new Map<string, TreeNode>();
const rootNodes = allNodes.filter((n) => n.data.level === 0);
const addVisibleChildren = (node: TreeNode) => {
visibleNodes.set(node.id, node);
if (expandedIds.has(node.id)) {
allNodes
.filter((n) => n.parentNode === node.id)
.forEach(addVisibleChildren);
}
};
rootNodes.forEach(addVisibleChildren);
return { nodes: Array.from(visibleNodes.values()) };
},
[],
);
memo 化节点 + memo 化样式边(命中重渲染热点):
const ProcessNode = memo(
({ data, selected }: NodeProps) => (
<div className={`process-node ${selected ? "selected" : ""}`}>{data.label}</div>
),
(prev, next) =>
prev.data.label === next.data.label &&
prev.selected === next.selected &&
prev.data.isExpanded === next.data.isExpanded,
);
const styledEdges = useMemo(
() =>
edges.map((edge) => ({
...edge,
style: {
...edge.style,
strokeWidth: selectedEdgeId === edge.id ? 3 : 2,
stroke: selectedEdgeId === edge.id ? "#3b82f6" : "#94a3b8",
},
animated: selectedEdgeId === edge.id,
})),
[edges, selectedEdgeId],
);
Dagre 自动布局(去抖 + 缓存):
import dagre from "dagre";
const layoutOptions = { rankdir: "TB", nodesep: 100, ranksep: 150, marginx: 50, marginy: 50, edgesep: 10 };
const applyLayout = (nodes: Node[], edges: Edge[]) => {
const g = new dagre.graphlib.Graph();
g.setGraph(layoutOptions);
g.setDefaultEdgeLabel(() => ({}));
nodes.forEach((n) => g.setNode(n.id, { width: 200, height: 100 }));
edges.forEach((e) => g.setEdge(e.source, e.target));
dagre.layout(g);
return nodes.map((n) => ({
...n,
position: { x: g.node(n.id).x - 100, y: g.node(n.id).y - 50 },
}));
};
const debouncedLayout = useMemo(() => debounce(applyLayout, 150), []);
Reducer 管展开/选中(撤销重做的基础):
type GraphAction =
| { type: "SELECT_NODE"; payload: string }
| { type: "TOGGLE_EXPAND"; payload: string }
| { type: "UNDO" } | { type: "REDO" };
const graphReducer = (state: GraphState, action: GraphAction): GraphState => {
switch (action.type) {
case "SELECT_NODE":
return { ...state, selectedNodeId: action.payload, selectedEdgeId: null };
case "TOGGLE_EXPAND": {
const next = new Set(state.expandedNodeIds);
next.has(action.payload) ? next.delete(action.payload) : next.add(action.payload);
return { ...state, expandedNodeIds: next, isDirty: true };
}
default:
return state;
}
};
聚焦模式(隔离选中节点及其直接连接):
const useFocusMode = (selectedNodeId: string, allNodes: Node[], allEdges: Edge[]) =>
useMemo(() => {
if (!selectedNodeId) return { nodes: allNodes, edges: allEdges };
const connected = new Set([selectedNodeId]);
const focusedEdges = allEdges.filter((e) => {
const hit = e.source === selectedNodeId || e.target === selectedNodeId;
if (hit) { connected.add(e.source); connected.add(e.target); }
return hit;
});
return { nodes: allNodes.filter((n) => connected.has(n.id)), edges: focusedEdges };
}, [selectedNodeId, allNodes, allEdges]);
注意事项
性能红线(来自源技能的硬约束):
- 节点 > 500 → 上虚拟化或裁剪可见节点;> 1000 必须虚拟化。
- 单帧估算 > 16ms 会掉 60fps → 用 memo 化 + 增量渲染。
- 节点组件统一
React.memo;边创建/操作函数用useCallback,依赖要稳定。 - 高频交互(拖拽、连续展开)时
debounce布局计算并缓存结果。
内存与状态:
- 用
Map做 O(1) 查找,替代array.find:new Map(allNodes.map((n) => [n.id, n]))。 useEffect返回清理函数,清空nodesMapRef/edgesMapRef等残留引用,必要时用WeakMap存临时数据。- 不该触发重渲染的对象(如自动保存数据)放
useRef,更新属性而非替换引用。
常见坑:
- 手动定位与自动布局冲突 → 用受控定位状态,分离「手动/自动」两种布局模式。
- 展开卡顿 → 增量渲染 + 变更检测(仅展开集变化时走增量更新,否则全量重建)。
- 过度重渲染 →
memo+useMemo+useCallback三件套,配稳定依赖。
边界提醒:本技能给的是估算式性能分析与模式,不能替代真实环境下的实测、Profiler 与专家评审;缺关键输入或约束时先暂停澄清。
互见
- 性能分析可配套一个静态扫描脚本(
scripts/graph-analyzer.js)统计节点/边数、估算渲染时间并给优化建议,用于 CI 或代码审查。 - 与「前端性能优化」「React 渲染优化」类技能配合使用效果更佳。
采编自 sickn33/antigravity-awesome-skills(MIT 许可证)。
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.