[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FVR0GDXADXMHPRKC2E941Z":3,"skill-same:01M6FVR0GDXADXMHPRKC2E941Z":72},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":50,"commitSha":51,"skillDirectory":52,"forksCount":14,"repositoryHtmlUrl":53,"repositoryHomepageUrl":6,"ownerHtmlUrl":54,"ownerBlogUrl":55,"ownerDescription":56,"updatedAt":57,"install":58,"resources":71},"01M6FVR0GDXADXMHPRKC2E941Z","react-flow-architect",null,"Expert ReactFlow architect for building interactive graph applications with hierarchical node-edge systems, performance optimization, and auto-layout integration. Use when Claude needs to create or...","reikiplanet\u002Fdaoskills","reikiplanet","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F96377599?v=4","01M6CVWCMD740YHQDK7E9QYBW4","Reiki Planet","01M6CVWCS4KXVA2CWFVJ43EAXK",0,"MIT","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fdevelopment\u002Freact-flow-architect\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"react","react flow architect","flow","architect","react flow","with","performance","layout","community","expert","auto","use","interactive","node","performance optimization","applications","Optimization","edge","graph","create","2026-11-10 10:12:30",false,"---\nname: react-flow-architect\ndescription: \"Expert ReactFlow architect for building interactive graph applications with hierarchical node-edge systems, performance optimization, and auto-layout integration. Use when Claude needs to create or...\"\nrisk: unknown\nsource: community\n---\n\n# ReactFlow Architect\n\nBuild production-ready ReactFlow applications with hierarchical navigation, performance optimization, and advanced state management.\n\n## Quick Start\n\nCreate basic interactive graph:\n\n```tsx\nimport ReactFlow, { Node, Edge } from \"reactflow\";\n\nconst nodes: Node[] = [\n  { id: \"1\", position: { x: 0, y: 0 }, data: { label: \"Node 1\" } },\n  { id: \"2\", position: { x: 100, y: 100 }, data: { label: \"Node 2\" } },\n];\n\nconst edges: Edge[] = [{ id: \"e1-2\", source: \"1\", target: \"2\" }];\n\nexport default function Graph() {\n  return \u003CReactFlow nodes={nodes} edges={edges} \u002F>;\n}\n```\n\n## Core Patterns\n\n### Hierarchical Tree Navigation\n\nBuild expandable\u002Fcollapsible tree structures with parent-child relationships.\n\n#### Node Schema\n\n```typescript\ninterface TreeNode extends Node {\n  data: {\n    label: string;\n    level: number;\n    hasChildren: boolean;\n    isExpanded: boolean;\n    childCount: number;\n    category: \"root\" | \"category\" | \"process\" | \"detail\";\n  };\n}\n```\n\n#### Incremental Node Building\n\n```typescript\nconst buildVisibleNodes = useCallback(\n  (allNodes: TreeNode[], expandedIds: Set\u003Cstring>, otherDeps: any[]) => {\n    const visibleNodes = new Map\u003Cstring, TreeNode>();\n    const visibleEdges = new Map\u003Cstring, TreeEdge>();\n\n    \u002F\u002F Start with root nodes\n    const rootNodes = allNodes.filter((n) => n.data.level === 0);\n\n    \u002F\u002F Recursively add visible nodes\n    const addVisibleChildren = (node: TreeNode) => {\n      visibleNodes.set(node.id, node);\n\n      if (expandedIds.has(node.id)) {\n        const children = allNodes.filter((n) => n.parentNode === node.id);\n        children.forEach((child) => addVisibleChildren(child));\n      }\n    };\n\n    rootNodes.forEach((root) => addVisibleChildren(root));\n\n    return {\n      nodes: Array.from(visibleNodes.values()),\n      edges: Array.from(visibleEdges.values()),\n    };\n  },\n  [],\n);\n```\n\n### Performance Optimization\n\nHandle large datasets with incremental rendering and memoization.\n\n#### Incremental Rendering\n\n```typescript\nconst useIncrementalGraph = (\n  allNodes: Node[],\n  allEdges: Edge[],\n  expandedList: string[],\n) => {\n  const prevExpandedListRef = useRef\u003CSet\u003Cstring>>(new Set());\n  const prevOtherDepsRef = useRef\u003Cany[]>([]);\n\n  const { visibleNodes, visibleEdges } = useMemo(() => {\n    const currentExpandedSet = new Set(expandedList);\n    const prevExpandedSet = prevExpandedListRef.current;\n\n    \u002F\u002F Check if expanded list changed\n    const expandedChanged = !areSetsEqual(currentExpandedSet, prevExpandedSet);\n\n    \u002F\u002F Check if other dependencies changed\n    const otherDepsChanged = !arraysEqual(otherDeps, prevOtherDepsRef.current);\n\n    if (expandedChanged && !otherDepsChanged) {\n      \u002F\u002F Only expanded list changed - incremental update\n      return buildIncrementalUpdate(\n        cachedVisibleNodesRef.current,\n        cachedVisibleEdgesRef.current,\n        allNodes,\n        allEdges,\n        currentExpandedSet,\n        prevExpandedSet,\n      );\n    } else {\n      \u002F\u002F Full rebuild needed\n      return buildFullGraph(allNodes, allEdges, currentExpandedSet);\n    }\n  }, [allNodes, allEdges, expandedList, ...otherDeps]);\n\n  return { visibleNodes, visibleEdges };\n};\n```\n\n#### Memoization Patterns\n\n```typescript\n\u002F\u002F Memoize node components to prevent unnecessary re-renders\nconst ProcessNode = memo(({ data, selected }: NodeProps) => {\n  return (\n    \u003Cdiv className={`process-node ${selected ? 'selected' : ''}`}>\n      {data.label}\n    \u003C\u002Fdiv>\n  );\n}, (prevProps, nextProps) => {\n  \u002F\u002F Custom comparison function\n  return (\n    prevProps.data.label === nextProps.data.label &&\n    prevProps.selected === nextProps.selected &&\n    prevProps.data.isExpanded === nextProps.data.isExpanded\n  );\n});\n\n\u002F\u002F Memoize edge calculations\nconst styledEdges = useMemo(() => {\n  return edges.map(edge => ({\n    ...edge,\n    style: {\n      ...edge.style,\n      strokeWidth: selectedEdgeId === edge.id ? 3 : 2,\n      stroke: selectedEdgeId === edge.id ? '#3b82f6' : '#94a3b8',\n    },\n    animated: selectedEdgeId === edge.id,\n  }));\n}, [edges, selectedEdgeId]);\n```\n\n### State Management\n\nComplex node\u002Fedge state patterns with undo\u002Fredo and persistence.\n\n#### Reducer Pattern\n\n```typescript\ntype GraphAction =\n  | { type: \"SELECT_NODE\"; payload: string }\n  | { type: \"SELECT_EDGE\"; payload: string }\n  | { type: \"TOGGLE_EXPAND\"; payload: string }\n  | { type: \"UPDATE_NODES\"; payload: Node[] }\n  | { type: \"UPDATE_EDGES\"; payload: Edge[] }\n  | { type: \"UNDO\" }\n  | { type: \"REDO\" };\n\nconst graphReducer = (state: GraphState, action: GraphAction): GraphState => {\n  switch (action.type) {\n    case \"SELECT_NODE\":\n      return {\n        ...state,\n        selectedNodeId: action.payload,\n        selectedEdgeId: null,\n      };\n\n    case \"TOGGLE_EXPAND\":\n      const newExpanded = new Set(state.expandedNodeIds);\n      if (newExpanded.has(action.payload)) {\n        newExpanded.delete(action.payload);\n      } else {\n        newExpanded.add(action.payload);\n      }\n      return {\n        ...state,\n        expandedNodeIds: newExpanded,\n        isDirty: true,\n      };\n\n    default:\n      return state;\n  }\n};\n```\n\n#### History Management\n\n```typescript\nconst useHistoryManager = (\n  state: GraphState,\n  dispatch: Dispatch\u003CGraphAction>,\n) => {\n  const canUndo = state.historyIndex > 0;\n  const canRedo = state.historyIndex \u003C state.history.length - 1;\n\n  const undo = useCallback(() => {\n    if (canUndo) {\n      const newIndex = state.historyIndex - 1;\n      const historyEntry = state.history[newIndex];\n\n      dispatch({\n        type: \"RESTORE_FROM_HISTORY\",\n        payload: {\n          ...historyEntry,\n          historyIndex: newIndex,\n        },\n      });\n    }\n  }, [canUndo, state.historyIndex, state.history]);\n\n  const saveToHistory = useCallback(() => {\n    dispatch({ type: \"SAVE_TO_HISTORY\" });\n  }, [dispatch]);\n\n  return { canUndo, canRedo, undo, redo, saveToHistory };\n};\n```\n\n## Advanced Features\n\n### Auto-Layout Integration\n\nIntegrate Dagre for automatic graph layout:\n\n```typescript\nimport dagre from \"dagre\";\n\nconst layoutOptions = {\n  rankdir: \"TB\", \u002F\u002F Top to Bottom\n  nodesep: 100, \u002F\u002F Node separation\n  ranksep: 150, \u002F\u002F Rank separation\n  marginx: 50,\n  marginy: 50,\n  edgesep: 10,\n};\n\nconst applyLayout = (nodes: Node[], edges: Edge[]) => {\n  const g = new dagre.graphlib.Graph();\n  g.setGraph(layoutOptions);\n  g.setDefaultEdgeLabel(() => ({}));\n\n  \u002F\u002F Add nodes to graph\n  nodes.forEach((node) => {\n    g.setNode(node.id, { width: 200, height: 100 });\n  });\n\n  \u002F\u002F Add edges to graph\n  edges.forEach((edge) => {\n    g.setEdge(edge.source, edge.target);\n  });\n\n  \u002F\u002F Calculate layout\n  dagre.layout(g);\n\n  \u002F\u002F Apply positions\n  return nodes.map((node) => ({\n    ...node,\n    position: {\n      x: g.node(node.id).x - 100,\n      y: g.node(node.id).y - 50,\n    },\n  }));\n};\n\n\u002F\u002F Debounce layout calculations\nconst debouncedLayout = useMemo(() => debounce(applyLayout, 150), []);\n```\n\n### Focus Mode\n\nIsolate selected nodes and their direct connections:\n\n```typescript\nconst useFocusMode = (\n  selectedNodeId: string,\n  allNodes: Node[],\n  allEdges: Edge[],\n) => {\n  return useMemo(() => {\n    if (!selectedNodeId) return { nodes: allNodes, edges: allEdges };\n\n    \u002F\u002F Get direct connections\n    const connectedNodeIds = new Set([selectedNodeId]);\n    const focusedEdges: Edge[] = [];\n\n    allEdges.forEach((edge) => {\n      if (edge.source === selectedNodeId || edge.target === selectedNodeId) {\n        focusedEdges.push(edge);\n        connectedNodeIds.add(edge.source);\n        connectedNodeIds.add(edge.target);\n      }\n    });\n\n    \u002F\u002F Get connected nodes\n    const focusedNodes = allNodes.filter((n) => connectedNodeIds.has(n.id));\n\n    return { nodes: focusedNodes, edges: focusedEdges };\n  }, [selectedNodeId, allNodes, allEdges]);\n};\n\n\u002F\u002F Smooth transitions for focus mode\nconst focusModeStyles = {\n  transition: \"all 0.3s ease-in-out\",\n  opacity: isInFocus ? 1 : 0.3,\n  filter: isInFocus ? \"none\" : \"blur(2px)\",\n};\n```\n\n### Search Integration\n\nSearch and navigate to specific nodes:\n\n```typescript\nconst searchNodes = useCallback((nodes: Node[], query: string) => {\n  if (!query.trim()) return [];\n\n  const lowerQuery = query.toLowerCase();\n  return nodes.filter(\n    (node) =>\n      node.data.label.toLowerCase().includes(lowerQuery) ||\n      node.data.description?.toLowerCase().includes(lowerQuery),\n  );\n}, []);\n\nconst navigateToSearchResult = (nodeId: string) => {\n  \u002F\u002F Expand parent nodes\n  const nodePath = calculateBreadcrumbPath(nodeId, allNodes);\n  const parentIds = nodePath.slice(0, -1).map((n) => n.id);\n\n  setExpandedIds((prev) => new Set([...prev, ...parentIds]));\n  setSelectedNodeId(nodeId);\n\n  \u002F\u002F Fit view to node\n  fitView({ nodes: [{ id: nodeId }], duration: 800 });\n};\n```\n\n## Performance Tools\n\n### Graph Performance Analyzer\n\nCreate a performance analysis script:\n\n```javascript\n\u002F\u002F scripts\u002Fgraph-analyzer.js\nclass GraphAnalyzer {\n  analyzeCode(content, filePath) {\n    const analysis = {\n      metrics: {\n        nodeCount: this.countNodes(content),\n        edgeCount: this.countEdges(content),\n        renderTime: this.estimateRenderTime(content),\n        memoryUsage: this.estimateMemoryUsage(content),\n        complexity: this.calculateComplexity(content),\n      },\n      issues: [],\n      optimizations: [],\n      patterns: this.detectPatterns(content),\n    };\n\n    \u002F\u002F Detect performance issues\n    this.detectPerformanceIssues(analysis);\n\n    \u002F\u002F Suggest optimizations\n    this.suggestOptimizations(analysis);\n\n    return analysis;\n  }\n\n  countNodes(content) {\n    const nodePatterns = [\n      \u002Fnodes:\\s*\\[.*?\\]\u002Fgs,\n      \u002Fconst\\s+\\w+\\s*=\\s*\\[.*?id:.*?position:\u002Fgs,\n    ];\n\n    let totalCount = 0;\n    nodePatterns.forEach((pattern) => {\n      const matches = content.match(pattern);\n      if (matches) {\n        matches.forEach((match) => {\n          const nodeMatches = match.match(\u002Fid:\\s*['\"`][^'\"`]+['\"`]\u002Fg);\n          if (nodeMatches) {\n            totalCount += nodeMatches.length;\n          }\n        });\n      }\n    });\n\n    return totalCount;\n  }\n\n  estimateRenderTime(content) {\n    const nodeCount = this.countNodes(content);\n    const edgeCount = this.countEdges(content);\n\n    \u002F\u002F Base render time estimation (ms)\n    const baseTime = 5;\n    const nodeTime = nodeCount * 0.1;\n    const edgeTime = edgeCount * 0.05;\n\n    return baseTime + nodeTime + edgeTime;\n  }\n\n  detectPerformanceIssues(analysis) {\n    const { metrics } = analysis;\n\n    if (metrics.nodeCount > 500) {\n      analysis.issues.push({\n        type: \"HIGH_NODE_COUNT\",\n        severity: \"high\",\n        message: `Too many nodes (${metrics.nodeCount}). Consider virtualization.`,\n        suggestion: \"Implement virtualization or reduce visible nodes\",\n      });\n    }\n\n    if (metrics.renderTime > 16) {\n      analysis.issues.push({\n        type: \"SLOW_RENDER\",\n        severity: \"high\",\n        message: `Render time (${metrics.renderTime.toFixed(2)}ms) exceeds 60fps.`,\n        suggestion: \"Optimize with memoization and incremental rendering\",\n      });\n    }\n  }\n}\n```\n\n## Best Practices\n\n### Performance Guidelines\n\n1. **Use React.memo** for node components to prevent unnecessary re-renders\n2. **Implement virtualization** for graphs with 1000+ nodes\n3. **Debounce layout calculations** during rapid interactions\n4. **Use useCallback** for edge creation and manipulation functions\n5. **Implement proper TypeScript types** for nodes and edges\n\n### Memory Management\n\n```typescript\n\u002F\u002F Use Map for O(1) lookups instead of array.find\nconst nodesById = useMemo(\n  () => new Map(allNodes.map((n) => [n.id, n])),\n  [allNodes],\n);\n\n\u002F\u002F Cache layout results\nconst layoutCacheRef = useRef\u003CMap\u003Cstring, Node[]>>(new Map());\n\n\u002F\u002F Proper cleanup in useEffect\nuseEffect(() => {\n  return () => {\n    \u002F\u002F Clean up any lingering references\n    nodesMapRef.current.clear();\n    edgesMapRef.current.clear();\n  };\n}, []);\n```\n\n### State Optimization\n\n```typescript\n\u002F\u002F Use useRef for objects that shouldn't trigger re-renders\nconst autoSaveDataRef = useRef({\n  nodes: [],\n  edges: [],\n  lastSaved: Date.now(),\n});\n\n\u002F\u002F Update properties without breaking reference\nconst updateAutoSaveData = (newNodes: Node[], newEdges: Edge[]) => {\n  autoSaveDataRef.current.nodes = newNodes;\n  autoSaveDataRef.current.edges = newEdges;\n  autoSaveDataRef.current.lastSaved = Date.now();\n};\n```\n\n## Common Problems & Solutions\n\n### Performance Issues\n\n- **Problem**: Lag during node expansion\n- **Solution**: Implement incremental rendering with change detection\n\n- **Problem**: Memory usage increases over time\n- **Solution**: Proper cleanup in useEffect hooks and use WeakMap for temporary data\n\n### Layout Conflicts\n\n- **Problem**: Manual positioning conflicts with auto-layout\n- **Solution**: Use controlled positioning state and separate layout modes\n\n### Rendering Issues\n\n- **Problem**: Excessive re-renders\n- **Solution**: Use memo, useMemo, and useCallback with stable dependencies\n\n- **Problem**: Slow layout calculations\n- **Solution**: Debounce layout calculations and cache results\n\n## Complete Example\n\n```typescript\nimport React, { useState, useCallback, useMemo, useRef } from 'react';\nimport ReactFlow, { Node, Edge, useReactFlow } from 'reactflow';\nimport dagre from 'dagre';\nimport { debounce } from 'lodash';\n\ninterface GraphState {\n  nodes: Node[];\n  edges: Edge[];\n  selectedNodeId: string | null;\n  expandedNodeIds: Set\u003Cstring>;\n  history: GraphState[];\n  historyIndex: number;\n}\n\nexport default function InteractiveGraph() {\n  const [state, setState] = useState\u003CGraphState>({\n    nodes: [],\n    edges: [],\n    selectedNodeId: null,\n    expandedNodeIds: new Set(),\n    history: [],\n    historyIndex: 0,\n  });\n\n  const { fitView } = useReactFlow();\n  const layoutCacheRef = useRef\u003CMap\u003Cstring, Node[]>>(new Map());\n\n  \u002F\u002F Memoized styled edges\n  const styledEdges = useMemo(() => {\n    return state.edges.map(edge => ({\n      ...edge,\n      style: {\n        ...edge.style,\n        strokeWidth: state.selectedNodeId === edge.source || state.selectedNodeId === edge.target ? 3 : 2,\n        stroke: state.selectedNodeId === edge.source || state.selectedNodeId === edge.target ? '#3b82f6' : '#94a3b8',\n      },\n      animated: state.selectedNodeId === edge.source || state.selectedNodeId === edge.target,\n    }));\n  }, [state.edges, state.selectedNodeId]);\n\n  \u002F\u002F Debounced layout calculation\n  const debouncedLayout = useMemo(\n    () => debounce((nodes: Node[], edges: Edge[]) => {\n      const cacheKey = generateLayoutCacheKey(nodes, edges);\n\n      if (layoutCacheRef.current.has(cacheKey)) {\n        return layoutCacheRef.current.get(cacheKey)!;\n      }\n\n      const layouted = applyDagreLayout(nodes, edges);\n      layoutCacheRef.current.set(cacheKey, layouted);\n\n      return layouted;\n    }, 150),\n    []\n  );\n\n  const handleNodeClick = useCallback((event: React.MouseEvent, node: Node) => {\n    setState(prev => ({\n      ...prev,\n      selectedNodeId: node.id,\n    }));\n  }, []);\n\n  const handleToggleExpand = useCallback((nodeId: string) => {\n    setState(prev => {\n      const newExpanded = new Set(prev.expandedNodeIds);\n      if (newExpanded.has(nodeId)) {\n        newExpanded.delete(nodeId);\n      } else {\n        newExpanded.add(nodeId);\n      }\n\n      return {\n        ...prev,\n        expandedNodeIds: newExpanded,\n      };\n    });\n  }, []);\n\n  return (\n    \u003CReactFlow\n      nodes={state.nodes}\n      edges={styledEdges}\n      onNodeClick={handleNodeClick}\n      fitView\n    \u002F>\n  );\n}\n```\n\nThis comprehensive skill provides everything needed to build production-ready ReactFlow applications with hierarchical navigation, performance optimization, and advanced state management patterns.\n\n## When to Use\nThis skill is applicable to execute the workflow or actions described in the overview.\n","# ReactFlow Architect\n\nBuild production-ready ReactFlow applications with hierarchical navigation, performance optimization, and advanced state management.\n\n## Quick Start\n\nCreate basic interactive graph:\n\n```tsx\nimport ReactFlow, { Node, Edge } from \"reactflow\";\n\nconst nodes: Node[] = [\n  { id: \"1\", position: { x: 0, y: 0 }, data: { label: \"Node 1\" } },\n  { id: \"2\", position: { x: 100, y: 100 }, data: { label: \"Node 2\" } },\n];\n\nconst edges: Edge[] = [{ id: \"e1-2\", source: \"1\", target: \"2\" }];\n\nexport default function Graph() {\n  return \u003CReactFlow nodes={nodes} edges={edges} \u002F>;\n}\n```\n\n## Core Patterns\n\n### Hierarchical Tree Navigation\n\nBuild expandable\u002Fcollapsible tree structures with parent-child relationships.\n\n#### Node Schema\n\n```typescript\ninterface TreeNode extends Node {\n  data: {\n    label: string;\n    level: number;\n    hasChildren: boolean;\n    isExpanded: boolean;\n    childCount: number;\n    category: \"root\" | \"category\" | \"process\" | \"detail\";\n  };\n}\n```\n\n#### Incremental Node Building\n\n```typescript\nconst buildVisibleNodes = useCallback(\n  (allNodes: TreeNode[], expandedIds: Set\u003Cstring>, otherDeps: any[]) => {\n    const visibleNodes = new Map\u003Cstring, TreeNode>();\n    const visibleEdges = new Map\u003Cstring, TreeEdge>();\n\n    \u002F\u002F Start with root nodes\n    const rootNodes = allNodes.filter((n) => n.data.level === 0);\n\n    \u002F\u002F Recursively add visible nodes\n    const addVisibleChildren = (node: TreeNode) => {\n      visibleNodes.set(node.id, node);\n\n      if (expandedIds.has(node.id)) {\n        const children = allNodes.filter((n) => n.parentNode === node.id);\n        children.forEach((child) => addVisibleChildren(child));\n      }\n    };\n\n    rootNodes.forEach((root) => addVisibleChildren(root));\n\n    return {\n      nodes: Array.from(visibleNodes.values()),\n      edges: Array.from(visibleEdges.values()),\n    };\n  },\n  [],\n);\n```\n\n### Performance Optimization\n\nHandle large datasets with incremental rendering and memoization.\n\n#### Incremental Rendering\n\n```typescript\nconst useIncrementalGraph = (\n  allNodes: Node[],\n  allEdges: Edge[],\n  expandedList: string[],\n) => {\n  const prevExpandedListRef = useRef\u003CSet\u003Cstring>>(new Set());\n  const prevOtherDepsRef = useRef\u003Cany[]>([]);\n\n  const { visibleNodes, visibleEdges } = useMemo(() => {\n    const currentExpandedSet = new Set(expandedList);\n    const prevExpandedSet = prevExpandedListRef.current;\n\n    \u002F\u002F Check if expanded list changed\n    const expandedChanged = !areSetsEqual(currentExpandedSet, prevExpandedSet);\n\n    \u002F\u002F Check if other dependencies changed\n    const otherDepsChanged = !arraysEqual(otherDeps, prevOtherDepsRef.current);\n\n    if (expandedChanged && !otherDepsChanged) {\n      \u002F\u002F Only expanded list changed - incremental update\n      return buildIncrementalUpdate(\n        cachedVisibleNodesRef.current,\n        cachedVisibleEdgesRef.current,\n        allNodes,\n        allEdges,\n        currentExpandedSet,\n        prevExpandedSet,\n      );\n    } else {\n      \u002F\u002F Full rebuild needed\n      return buildFullGraph(allNodes, allEdges, currentExpandedSet);\n    }\n  }, [allNodes, allEdges, expandedList, ...otherDeps]);\n\n  return { visibleNodes, visibleEdges };\n};\n```\n\n#### Memoization Patterns\n\n```typescript\n\u002F\u002F Memoize node components to prevent unnecessary re-renders\nconst ProcessNode = memo(({ data, selected }: NodeProps) => {\n  return (\n    \u003Cdiv className={`process-node ${selected ? 'selected' : ''}`}>\n      {data.label}\n    \u003C\u002Fdiv>\n  );\n}, (prevProps, nextProps) => {\n  \u002F\u002F Custom comparison function\n  return (\n    prevProps.data.label === nextProps.data.label &&\n    prevProps.selected === nextProps.selected &&\n    prevProps.data.isExpanded === nextProps.data.isExpanded\n  );\n});\n\n\u002F\u002F Memoize edge calculations\nconst styledEdges = useMemo(() => {\n  return edges.map(edge => ({\n    ...edge,\n    style: {\n      ...edge.style,\n      strokeWidth: selectedEdgeId === edge.id ? 3 : 2,\n      stroke: selectedEdgeId === edge.id ? '#3b82f6' : '#94a3b8',\n    },\n    animated: selectedEdgeId === edge.id,\n  }));\n}, [edges, selectedEdgeId]);\n```\n\n### State Management\n\nComplex node\u002Fedge state patterns with undo\u002Fredo and persistence.\n\n#### Reducer Pattern\n\n```typescript\ntype GraphAction =\n  | { type: \"SELECT_NODE\"; payload: string }\n  | { type: \"SELECT_EDGE\"; payload: string }\n  | { type: \"TOGGLE_EXPAND\"; payload: string }\n  | { type: \"UPDATE_NODES\"; payload: Node[] }\n  | { type: \"UPDATE_EDGES\"; payload: Edge[] }\n  | { type: \"UNDO\" }\n  | { type: \"REDO\" };\n\nconst graphReducer = (state: GraphState, action: GraphAction): GraphState => {\n  switch (action.type) {\n    case \"SELECT_NODE\":\n      return {\n        ...state,\n        selectedNodeId: action.payload,\n        selectedEdgeId: null,\n      };\n\n    case \"TOGGLE_EXPAND\":\n      const newExpanded = new Set(state.expandedNodeIds);\n      if (newExpanded.has(action.payload)) {\n        newExpanded.delete(action.payload);\n      } else {\n        newExpanded.add(action.payload);\n      }\n      return {\n        ...state,\n        expandedNodeIds: newExpanded,\n        isDirty: true,\n      };\n\n    default:\n      return state;\n  }\n};\n```\n\n#### History Management\n\n```typescript\nconst useHistoryManager = (\n  state: GraphState,\n  dispatch: Dispatch\u003CGraphAction>,\n) => {\n  const canUndo = state.historyIndex > 0;\n  const canRedo = state.historyIndex \u003C state.history.length - 1;\n\n  const undo = useCallback(() => {\n    if (canUndo) {\n      const newIndex = state.historyIndex - 1;\n      const historyEntry = state.history[newIndex];\n\n      dispatch({\n        type: \"RESTORE_FROM_HISTORY\",\n        payload: {\n          ...historyEntry,\n          historyIndex: newIndex,\n        },\n      });\n    }\n  }, [canUndo, state.historyIndex, state.history]);\n\n  const saveToHistory = useCallback(() => {\n    dispatch({ type: \"SAVE_TO_HISTORY\" });\n  }, [dispatch]);\n\n  return { canUndo, canRedo, undo, redo, saveToHistory };\n};\n```\n\n## Advanced Features\n\n### Auto-Layout Integration\n\nIntegrate Dagre for automatic graph layout:\n\n```typescript\nimport dagre from \"dagre\";\n\nconst layoutOptions = {\n  rankdir: \"TB\", \u002F\u002F Top to Bottom\n  nodesep: 100, \u002F\u002F Node separation\n  ranksep: 150, \u002F\u002F Rank separation\n  marginx: 50,\n  marginy: 50,\n  edgesep: 10,\n};\n\nconst applyLayout = (nodes: Node[], edges: Edge[]) => {\n  const g = new dagre.graphlib.Graph();\n  g.setGraph(layoutOptions);\n  g.setDefaultEdgeLabel(() => ({}));\n\n  \u002F\u002F Add nodes to graph\n  nodes.forEach((node) => {\n    g.setNode(node.id, { width: 200, height: 100 });\n  });\n\n  \u002F\u002F Add edges to graph\n  edges.forEach((edge) => {\n    g.setEdge(edge.source, edge.target);\n  });\n\n  \u002F\u002F Calculate layout\n  dagre.layout(g);\n\n  \u002F\u002F Apply positions\n  return nodes.map((node) => ({\n    ...node,\n    position: {\n      x: g.node(node.id).x - 100,\n      y: g.node(node.id).y - 50,\n    },\n  }));\n};\n\n\u002F\u002F Debounce layout calculations\nconst debouncedLayout = useMemo(() => debounce(applyLayout, 150), []);\n```\n\n### Focus Mode\n\nIsolate selected nodes and their direct connections:\n\n```typescript\nconst useFocusMode = (\n  selectedNodeId: string,\n  allNodes: Node[],\n  allEdges: Edge[],\n) => {\n  return useMemo(() => {\n    if (!selectedNodeId) return { nodes: allNodes, edges: allEdges };\n\n    \u002F\u002F Get direct connections\n    const connectedNodeIds = new Set([selectedNodeId]);\n    const focusedEdges: Edge[] = [];\n\n    allEdges.forEach((edge) => {\n      if (edge.source === selectedNodeId || edge.target === selectedNodeId) {\n        focusedEdges.push(edge);\n        connectedNodeIds.add(edge.source);\n        connectedNodeIds.add(edge.target);\n      }\n    });\n\n    \u002F\u002F Get connected nodes\n    const focusedNodes = allNodes.filter((n) => connectedNodeIds.has(n.id));\n\n    return { nodes: focusedNodes, edges: focusedEdges };\n  }, [selectedNodeId, allNodes, allEdges]);\n};\n\n\u002F\u002F Smooth transitions for focus mode\nconst focusModeStyles = {\n  transition: \"all 0.3s ease-in-out\",\n  opacity: isInFocus ? 1 : 0.3,\n  filter: isInFocus ? \"none\" : \"blur(2px)\",\n};\n```\n\n### Search Integration\n\nSearch and navigate to specific nodes:\n\n```typescript\nconst searchNodes = useCallback((nodes: Node[], query: string) => {\n  if (!query.trim()) return [];\n\n  const lowerQuery = query.toLowerCase();\n  return nodes.filter(\n    (node) =>\n      node.data.label.toLowerCase().includes(lowerQuery) ||\n      node.data.description?.toLowerCase().includes(lowerQuery),\n  );\n}, []);\n\nconst navigateToSearchResult = (nodeId: string) => {\n  \u002F\u002F Expand parent nodes\n  const nodePath = calculateBreadcrumbPath(nodeId, allNodes);\n  const parentIds = nodePath.slice(0, -1).map((n) => n.id);\n\n  setExpandedIds((prev) => new Set([...prev, ...parentIds]));\n  setSelectedNodeId(nodeId);\n\n  \u002F\u002F Fit view to node\n  fitView({ nodes: [{ id: nodeId }], duration: 800 });\n};\n```\n\n## Performance Tools\n\n### Graph Performance Analyzer\n\nCreate a performance analysis script:\n\n```javascript\n\u002F\u002F scripts\u002Fgraph-analyzer.js\nclass GraphAnalyzer {\n  analyzeCode(content, filePath) {\n    const analysis = {\n      metrics: {\n        nodeCount: this.countNodes(content),\n        edgeCount: this.countEdges(content),\n        renderTime: this.estimateRenderTime(content),\n        memoryUsage: this.estimateMemoryUsage(content),\n        complexity: this.calculateComplexity(content),\n      },\n      issues: [],\n      optimizations: [],\n      patterns: this.detectPatterns(content),\n    };\n\n    \u002F\u002F Detect performance issues\n    this.detectPerformanceIssues(analysis);\n\n    \u002F\u002F Suggest optimizations\n    this.suggestOptimizations(analysis);\n\n    return analysis;\n  }\n\n  countNodes(content) {\n    const nodePatterns = [\n      \u002Fnodes:\\s*\\[.*?\\]\u002Fgs,\n      \u002Fconst\\s+\\w+\\s*=\\s*\\[.*?id:.*?position:\u002Fgs,\n    ];\n\n    let totalCount = 0;\n    nodePatterns.forEach((pattern) => {\n      const matches = content.match(pattern);\n      if (matches) {\n        matches.forEach((match) => {\n          const nodeMatches = match.match(\u002Fid:\\s*['\"`][^'\"`]+['\"`]\u002Fg);\n          if (nodeMatches) {\n            totalCount += nodeMatches.length;\n          }\n        });\n      }\n    });\n\n    return totalCount;\n  }\n\n  estimateRenderTime(content) {\n    const nodeCount = this.countNodes(content);\n    const edgeCount = this.countEdges(content);\n\n    \u002F\u002F Base render time estimation (ms)\n    const baseTime = 5;\n    const nodeTime = nodeCount * 0.1;\n    const edgeTime = edgeCount * 0.05;\n\n    return baseTime + nodeTime + edgeTime;\n  }\n\n  detectPerformanceIssues(analysis) {\n    const { metrics } = analysis;\n\n    if (metrics.nodeCount > 500) {\n      analysis.issues.push({\n        type: \"HIGH_NODE_COUNT\",\n        severity: \"high\",\n        message: `Too many nodes (${metrics.nodeCount}). Consider virtualization.`,\n        suggestion: \"Implement virtualization or reduce visible nodes\",\n      });\n    }\n\n    if (metrics.renderTime > 16) {\n      analysis.issues.push({\n        type: \"SLOW_RENDER\",\n        severity: \"high\",\n        message: `Render time (${metrics.renderTime.toFixed(2)}ms) exceeds 60fps.`,\n        suggestion: \"Optimize with memoization and incremental rendering\",\n      });\n    }\n  }\n}\n```\n\n## Best Practices\n\n### Performance Guidelines\n\n1. **Use React.memo** for node components to prevent unnecessary re-renders\n2. **Implement virtualization** for graphs with 1000+ nodes\n3. **Debounce layout calculations** during rapid interactions\n4. **Use useCallback** for edge creation and manipulation functions\n5. **Implement proper TypeScript types** for nodes and edges\n\n### Memory Management\n\n```typescript\n\u002F\u002F Use Map for O(1) lookups instead of array.find\nconst nodesById = useMemo(\n  () => new Map(allNodes.map((n) => [n.id, n])),\n  [allNodes],\n);\n\n\u002F\u002F Cache layout results\nconst layoutCacheRef = useRef\u003CMap\u003Cstring, Node[]>>(new Map());\n\n\u002F\u002F Proper cleanup in useEffect\nuseEffect(() => {\n  return () => {\n    \u002F\u002F Clean up any lingering references\n    nodesMapRef.current.clear();\n    edgesMapRef.current.clear();\n  };\n}, []);\n```\n\n### State Optimization\n\n```typescript\n\u002F\u002F Use useRef for objects that shouldn't trigger re-renders\nconst autoSaveDataRef = useRef({\n  nodes: [],\n  edges: [],\n  lastSaved: Date.now(),\n});\n\n\u002F\u002F Update properties without breaking reference\nconst updateAutoSaveData = (newNodes: Node[], newEdges: Edge[]) => {\n  autoSaveDataRef.current.nodes = newNodes;\n  autoSaveDataRef.current.edges = newEdges;\n  autoSaveDataRef.current.lastSaved = Date.now();\n};\n```\n\n## Common Problems & Solutions\n\n### Performance Issues\n\n- **Problem**: Lag during node expansion\n- **Solution**: Implement incremental rendering with change detection\n\n- **Problem**: Memory usage increases over time\n- **Solution**: Proper cleanup in useEffect hooks and use WeakMap for temporary data\n\n### Layout Conflicts\n\n- **Problem**: Manual positioning conflicts with auto-layout\n- **Solution**: Use controlled positioning state and separate layout modes\n\n### Rendering Issues\n\n- **Problem**: Excessive re-renders\n- **Solution**: Use memo, useMemo, and useCallback with stable dependencies\n\n- **Problem**: Slow layout calculations\n- **Solution**: Debounce layout calculations and cache results\n\n## Complete Example\n\n```typescript\nimport React, { useState, useCallback, useMemo, useRef } from 'react';\nimport ReactFlow, { Node, Edge, useReactFlow } from 'reactflow';\nimport dagre from 'dagre';\nimport { debounce } from 'lodash';\n\ninterface GraphState {\n  nodes: Node[];\n  edges: Edge[];\n  selectedNodeId: string | null;\n  expandedNodeIds: Set\u003Cstring>;\n  history: GraphState[];\n  historyIndex: number;\n}\n\nexport default function InteractiveGraph() {\n  const [state, setState] = useState\u003CGraphState>({\n    nodes: [],\n    edges: [],\n    selectedNodeId: null,\n    expandedNodeIds: new Set(),\n    history: [],\n    historyIndex: 0,\n  });\n\n  const { fitView } = useReactFlow();\n  const layoutCacheRef = useRef\u003CMap\u003Cstring, Node[]>>(new Map());\n\n  \u002F\u002F Memoized styled edges\n  const styledEdges = useMemo(() => {\n    return state.edges.map(edge => ({\n      ...edge,\n      style: {\n        ...edge.style,\n        strokeWidth: state.selectedNodeId === edge.source || state.selectedNodeId === edge.target ? 3 : 2,\n        stroke: state.selectedNodeId === edge.source || state.selectedNodeId === edge.target ? '#3b82f6' : '#94a3b8',\n      },\n      animated: state.selectedNodeId === edge.source || state.selectedNodeId === edge.target,\n    }));\n  }, [state.edges, state.selectedNodeId]);\n\n  \u002F\u002F Debounced layout calculation\n  const debouncedLayout = useMemo(\n    () => debounce((nodes: Node[], edges: Edge[]) => {\n      const cacheKey = generateLayoutCacheKey(nodes, edges);\n\n      if (layoutCacheRef.current.has(cacheKey)) {\n        return layoutCacheRef.current.get(cacheKey)!;\n      }\n\n      const layouted = applyDagreLayout(nodes, edges);\n      layoutCacheRef.current.set(cacheKey, layouted);\n\n      return layouted;\n    }, 150),\n    []\n  );\n\n  const handleNodeClick = useCallback((event: React.MouseEvent, node: Node) => {\n    setState(prev => ({\n      ...prev,\n      selectedNodeId: node.id,\n    }));\n  }, []);\n\n  const handleToggleExpand = useCallback((nodeId: string) => {\n    setState(prev => {\n      const newExpanded = new Set(prev.expandedNodeIds);\n      if (newExpanded.has(nodeId)) {\n        newExpanded.delete(nodeId);\n      } else {\n        newExpanded.add(nodeId);\n      }\n\n      return {\n        ...prev,\n        expandedNodeIds: newExpanded,\n      };\n    });\n  }, []);\n\n  return (\n    \u003CReactFlow\n      nodes={state.nodes}\n      edges={styledEdges}\n      onNodeClick={handleNodeClick}\n      fitView\n    \u002F>\n  );\n}\n```\n\nThis comprehensive skill provides everything needed to build production-ready ReactFlow applications with hierarchical navigation, performance optimization, and advanced state management patterns.\n\n## When to Use\nThis skill is applicable to execute the workflow or actions described in the overview.\n",{"name":5,"risk":49,"source":32,"description":7},"unknown","master","dff58085da947e81e8418c922055644bf0082b1b","development\u002Freact-flow-architect","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills","https:\u002F\u002Fgithub.com\u002Freikiplanet","https:\u002F\u002Fwww.reiki-planet.com","Reiki Planet Game","2026-03-29 06:02:29",{"source":8,"skillName":5,"commands":59,"prompt":69,"zipAvailable":70},[60,63,66],{"tool":61,"command":62},"npx","npx skills add reikiplanet\u002Fdaoskills --skill react-flow-architect",{"tool":64,"command":65},"bunx","bunx skills add reikiplanet\u002Fdaoskills --skill react-flow-architect",{"tool":67,"command":68},"pnpm","pnpm dlx skills add reikiplanet\u002Fdaoskills --skill react-flow-architect","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fdevelopment\u002Freact-flow-architect\u002FSKILL.md",true,[],[73,98,109,122,141,164],{"skillNo":74,"name":75,"nameZh":6,"description":76,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":77,"categories":78,"keywords":79,"publishedAt":44},"01M6G614JTEQJHPT8AKK3YQ18S","web-games","Web browser game development principles. Framework selection, WebGPU, optimization, PWA.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fweb-games\u002FSKILL.md",[],[80,81,82,83,84,85,32,86,87,88,89,90,91,92,93,40,94,95,96,97],"games","web games","web","grep","principles","selection","framework selection","edit","write","read","pwa","game","web browser","game development","framework","browser","development","webgpu",{"skillNo":99,"name":100,"nameZh":6,"description":101,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":102,"categories":103,"keywords":104,"publishedAt":44},"01M6G611H2YGV0GZFP90D38ZMJ","vr-ar","VR\u002FAR development principles. Comfort, interaction, performance requirements.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fvr-ar\u002FSKILL.md",[],[105,106,96,107,108,32,87,88,89,83,30,84],"ar","vr ar","interaction","requirements",{"skillNo":110,"name":111,"nameZh":6,"description":112,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":113,"categories":114,"keywords":115,"publishedAt":44},"01M6G60XNMHAMV1SV0EJ1CX0AY","templates","Project scaffolding templates for new applications. Use when creating new projects from scratch. Contains 12 templates for various tech stacks.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Ftemplates\u002FSKILL.md",[],[111,116,117,118,119,120,32,35,89,121,39,83],"project scaffolding","From Scratch","tech","project","scaffolding","projects",{"skillNo":123,"name":124,"nameZh":6,"description":125,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":128,"publishedAt":44},"01M6G60T0GATMK3Q5H8GDC1Z8S","wcag-audit-patterns","Conduct WCAG 2.2 accessibility audits with automated testing, manual verification, and remediation guidance. Use when auditing websites for accessibility, fixing WCAG violations, or implementing ac...","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsecurity\u002Fwcag-audit-patterns\u002FSKILL.md",[],[129,130,131,132,133,32,134,29,135,136,35,137,138,139,140],"wcag audit patterns","wcag audit","patterns","WCAG","audit","manual","automated testing","guidance","remediation","verification","accessibility","testing",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":147,"publishedAt":44},"01M6G60PMCHW1FRZ63F931QK3R","vulnerability-scanner","Advanced vulnerability analysis principles. OWASP 2025, Supply Chain Security, attack surface mapping, risk prioritization.","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsecurity\u002Fvulnerability-scanner\u002FSKILL.md",[],[148,149,150,151,152,153,154,155,32,89,83,156,84,157,158,159,160,161,162,163],"scanner","vulnerability scanner","vulnerability","prioritization","2025","mapping","chain","supply chain","Bash","analysis","risk","owasp","supply chain security","security","supply","advanced",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":170,"publishedAt":44},"01M6G60JZBB8DK0W3DSG1WNMZK","threat-modeling-expert","Expert in threat modeling methodologies, security architecture review, and risk assessment. Masters STRIDE, PASTA, attack trees, and security requirement extraction. Use for security architecture r...","https:\u002F\u002Fgithub.com\u002Freikiplanet\u002Fdaoskills\u002Fblob\u002Fmaster\u002Fskills\u002Fsecurity\u002Fthreat-modeling-expert\u002FSKILL.md",[],[171,172,173,33,174,175,176,177,161,35,178,179,180,32,181,182,183,158,184,185],"modeling","threat modeling expert","threat modeling","threat","risk assessment","architecture review","architecture","security architecture review","trees","security architecture","security requirement extraction","assessment","extraction","review","stride"]