React Flow应用报错:Invalid hook call 问题排查与解决求助
React Flow 应用出现 Invalid hook call 错误的原因及解决方法
错误现象
应用抛出错误:Invalid hook call. Hooks can only be called inside of the body of a function component,即使简化LoadData函数后仍报错。
原代码示例
LoadData 函数
function LoadData() { const [graphData, setJsonResults] = useState([]); useEffect(() => { async function fetchData() { const data = await GetData(); setJsonResults(data); } fetchData(); }, []); return ( <div> {graphData.map((item, index) => ( <p key={index}>{item}</p> ))} </div> ); }
App 组件
export default function App() { const [nodes, setNodes] = useState([]); const [edges, setEdges] = useState([]); return ( <div style={{ width: '100vw', height: '100vh' }}> <button className="MyNewButton" onClick={LoadData}>Load Data</button> <ReactFlow nodes={nodes} edges={edges} onNodesChange={setNodes} onEdgesChange={setEdges} > <Controls /> <MiniMap /> <Background variant="dots" gap={12} size={1} /> </ReactFlow> </div> ); }
修改后仍报错的 LoadData 函数
const LoadData =()=>{ const [graphData, setJsonResults] = useState([]); return ( <div> Happy Days are here again </div> ) }
依赖版本信息
package.json
{ "name": "my-react-flow-app", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }, "dependencies": { "antd": "^5.3.3", "neo4j-driver": "^5.6.0", "react": "^18.2.0", "react-dom": "^18.2.0", "reactflow": "^11.7.0" }, "devDependencies": { "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", "@vitejs/plugin-react": "^3.1.0", "vite": "^4.2.0" } }
npm ls react-dom 结果
npm ls react-dom ├─┬ antd@5.3.3 │ ├─┬ @ant-design/cssinjs@1.7.1 │ │ └── react-dom@18.2.0 deduped │ ├─┬ @ant-design/icons@5.0.1 │ │ └── react-dom@18.2.0 deduped │ ├─┬ @rc-component/mutate-observer@1.0.0 │ │ └── react-dom@18.2.0 deduped │ ├─┬ @rc-component/tour@1.8.0 │ │ ├─┬ @rc-component/portal@1.1.1 │ │ │ └── react-dom@18.2.0 deduped │ │ └── react-dom@18.2.0 deduped │ ├─┬ @rc-component/trigger@1.6.2 │ │ ├─┬ rc-align@4.0.15 │ │ │ └── react-dom@18.2.0 deduped │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-cascader@3.9.1 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-checkbox@2.3.2 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-collapse@3.5.2 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-dialog@9.0.2 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-drawer@6.1.5 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-dropdown@4.0.1 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-field-form@1.28.0 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-image@5.15.2 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-input-number@7.4.2 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-input@0.2.2 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-mentions@2.1.0 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-menu@9.8.3 │ │ ├─┬ rc-overflow@1.3.0 │ │ │ └── react-dom@18.2.0 deduped │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-motion@2.6.3 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-notification@5.0.3 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-pagination@3.3.1 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-picker@3.3.4 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-progress@3.4.1 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-rate@2.10.0 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-resize-observer@1.3.1 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-segmented@2.1.2 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-select@14.3.0 │ │ ├─┬ rc-virtual-list@3.4.13 │ │ │ └── react-dom@18.2.0 deduped │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-slider@10.1.1 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-steps@6.0.0 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-switch@4.0.0 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-table@7.31.1 │ │ ├─┬ @rc-component/context@1.3.0 │ │ │ └── react-dom@18.2.0 deduped │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-tabs@12.5.10 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-textarea@1.1.0 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-tooltip@6.0.1 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-tree-select@5.7.0 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-tree@5.7.3 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-trigger@5.3.4 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-upload@4.3.4 │ │ └── react-dom@18.2.0 deduped │ ├─┬ rc-util@5.29.3 │ │ └── react-dom@18.2.0 deduped │ └── react-dom@18.2.0 deduped ├── react-dom@18.2.0 └─┬ reactflow@11.7.0 ├─┬ @reactflow/background@11.2.0 │ └── react-dom@18.2.0 deduped ├─┬ @reactflow/controls@11.1.11 │ └── react-dom@18.2.0 deduped ├─┬ @reactflow/core@11.7.0 │ └── react-dom@18.2.0 deduped ├─┬ @reactflow/minimap@11.5.0 │ └── react-dom@18.2.0 deduped ├─┬ @reactflow/node-resizer@2.1.0 │ └── react-dom@18.2.0 deduped ├─┬ @reactflow/node-toolbar@1.1.11 │ └── react-dom@18.2.0 deduped └── react-dom@18.2.0 deduped
错误原因
你把函数组件LoadData当成普通事件处理函数直接在onClick中调用了。React组件必须通过JSX语法(如<LoadData />)渲染,这样React才能在组件渲染周期内管理其中的Hooks。直接调用LoadData()相当于执行普通函数,里面的useState和useEffect不在React组件的渲染上下文中执行,违反了Hooks的使用规则,因此抛出错误。
解决方案
根据需求分两种情况处理:
情况1:点击按钮后显示LoadData的渲染内容
在App组件中添加状态控制LoadData的显示,将其作为组件渲染而非事件处理函数:
export default function App() { const [nodes, setNodes] = useState([]); const [edges, setEdges] = useState([]); const [showData, setShowData] = useState(false); // 新增状态控制显示 return ( <div style={{ width: '100vw', height: '100vh' }}> <button className="MyNewButton" onClick={() => setShowData(true)}>Load Data</button> {/* 条件渲染LoadData组件 */} {showData && <LoadData />} <ReactFlow nodes={nodes} edges={edges} onNodesChange={setNodes} onEdgesChange={setEdges} > <Controls /> <MiniMap /> <Background variant="dots" gap={12} size={1} /> </ReactFlow> </div> ); }
情况2:点击按钮后加载数据并更新React Flow的节点/边
如果目标是加载数据后更新React Flow的nodes和edges,无需渲染额外内容,直接将数据加载逻辑移到App组件的事件处理函数中:
export default function App() { const [nodes, setNodes] = useState([]); const [edges, setEdges] = useState([]); // 直接在App内定义事件处理函数 const handleLoadData = async () => { const data = await GetData(); // 根据实际数据格式转换为React Flow所需的节点/边结构 setNodes(data.nodes || []); setEdges(data.edges || []); }; return ( <div style={{ width: '100vw', height: '100vh' }}> <button className="MyNewButton" onClick={handleLoadData}>Load Data</button> <ReactFlow nodes={nodes} edges={edges} onNodesChange={setNodes} onEdgesChange={setEdges} > <Controls /> <MiniMap /> <Background variant="dots" gap={12} size={1} /> </ReactFlow> </div> ); }
内容的提问来源于stack exchange,提问作者spacedog
相关产品推荐
相关产品推荐

