[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-1c95f8b4-c6ed-4894-8ffb-86c9d16e23b8":3,"$fFDDwl8L3bXX8PxqEpeRPgM8gI5c5KtmekS58wlwa5Rs":43},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":34},"1c95f8b4-c6ed-4894-8ffb-86c9d16e23b8","react-flow-architect","构建具有分层导航、性能优化和高级状态管理的生产就绪ReactFlow应用程序。","cat_coding_frontend","mod_coding","sickn33,coding","---\nname: react-flow-architect\ndescription: \"Build production-ready ReactFlow applications with hierarchical navigation, performance optimization, and advanced state management.\"\nrisk: unknown\nsource: community\ndate_added: \"2026-02-27\"\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\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.\n","","imported","https:\u002F\u002Fgithub.com\u002Fsickn33\u002Fantigravity-awesome-skills","user_system_seed","SkillOPIC",true,84,1650,"2026-05-16 13:36:23",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":32,"skillCount":33,"createdAt":26},"前端开发","frontend","mdi-language-html5","HTML\u002FCSS\u002FJavaScript\u002F框架相关",1,96,[35],{"id":36,"skillId":4,"version":37,"fileName":38,"fileSize":39,"filePath":40,"fileHash":41,"manifest":42,"createdAt":19},"7b4e4751-53fc-43ac-921b-b7ad332aad24","1.0.0","react-flow-architect.zip",5432,"uploads\u002Fskills\u002F1c95f8b4-c6ed-4894-8ffb-86c9d16e23b8\u002Freact-flow-architect.zip","e7fe7bad00b63435bbddaee7ae6ed61c37c92413ecf77c8ccc748540d6990722","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":16243}]",{"code":44,"message":45,"data":46},200,"success",{"items":47,"stats":48,"page":51},[],{"averageRating":49,"totalRatings":49,"ratingCounts":50},0,[49,49,49,49,49],{"limit":52,"offset":49,"hasMore":53,"nextOffset":52,"ratedOnly":16},15,false]