React中Invalid hook call错误:TagCloud动态radius设置问题
解决方案
错误原因
触发Invalid hook call的核心问题是React钩子必须在函数组件的顶层作用域调用,不能嵌套在普通函数或useEffect这类生命周期钩子内部。你的Screening函数里直接调用了useWindowSize钩子,且该函数在useEffect内部执行,完全违反了React钩子的使用规则。
修复步骤
- 钩子移至组件顶层:直接在
Skills组件的顶层调用useWindowSize获取窗口尺寸,避免嵌套在其他函数中。 - 重构尺寸判断逻辑:将
Screening改为纯函数,接收窗口尺寸作为参数,返回对应radius值,不再依赖内部钩子。 - 处理窗口更新逻辑:把
windowSize加入useEffect的依赖数组,窗口尺寸变化时重新渲染TagCloud;同时用useRef保存TagCloud实例,更新前销毁旧实例避免内存泄漏。
修改后的完整代码
import { useEffect, useRef } from "react"; import "../Skills/Skills.css"; import useWindowSize from "./Screen"; const Skills = () => { const tagCloudInstance = useRef(null); // 保存TagCloud实例,用于更新时销毁 const windowSize = useWindowSize(); // 顶层调用钩子,符合规则 // 纯函数:根据窗口宽度返回对应radius const getRadius = (windowWidth) => { if (windowWidth > 1240) { return 250; } else if (windowWidth > 1000) { return 200; } else if (windowWidth > 900) { return 180; } else if (windowWidth > 750) { return 150; } else if (windowWidth > 600) { return 130; } else { return 200; } }; useEffect(() => { const TagCloud = require("TagCloud"); const container = ".content"; const myTags = ["JavaScript", "CSS"]; // 销毁旧实例,避免重复创建 if (tagCloudInstance.current) { tagCloudInstance.current.destroy(); } // 创建新的TagCloud实例 tagCloudInstance.current = TagCloud(container, myTags, { radius: getRadius(windowSize.width), maxSpeed: "normal", }); // 组件卸载时清理实例 return () => { if (tagCloudInstance.current) { tagCloudInstance.current.destroy(); } }; }, [windowSize]); // 依赖窗口尺寸,变化时重新执行 return ( <div className="skillsset" id="skills"> <h1 className="skills-title">Skills</h1> <div className="content"></div> {/* 确保存在目标容器元素 */} </div> ); }; export default Skills;
额外注意事项
- 确认
useWindowSize钩子能正确监听窗口resize事件并返回最新尺寸,否则会影响动态更新逻辑。 - 模板中必须存在
.contentDOM容器,否则TagCloud无法找到目标元素。 - 原
shouldLog逻辑已移除,因为现在依赖windowSize自动触发更新,无需限制执行次数。
内容的提问来源于stack exchange,提问作者Abhishek Srinivasan
相关产品推荐
相关产品推荐

