React自定义Hook导入报错:default非函数及Canvas适配问题问询
自定义Hook导入报错排查与优化方案
问题描述
导入自定义Hook useWindowsDimension 时,无论使用何种导入方式均出现以下报错:
Error: (0 , hooks_useWindowsDimension__WEBPACK_IMPORTED_MODULE_2_.default) is not a function.
自定义Hook代码:
"use client" import { useEffect, useState } from "react"; const useWindowsDimension = (): { width: number; height: number } => { const [windowDimension, setWindowDimension] = useState({ width: typeof window !== "undefined" ? window.innerHeight : 0, height: typeof window !== "undefined" ? window.innerHeight : 0, }); useEffect(() => { function handleResize(): void { setWindowDimension({ width: window.innerWidth, height: window.innerHeight, }); } window.addEventListener("resize", handleResize); handleResize(); return () => window.removeEventListener("resize", handleResize); }, []); return windowDimension; }; export default useWindowsDimension;
组件使用代码:
import useWindowsDimension from "@/hooks/useWindowsDimension"; export default function Home() { const { width, height } = useWindowsDimension(); return ( <div> <canvas className="bg-blue-500" width={width} height={height} /> </div> ); }
需求为页面重载时Canvas立即占满整个屏幕,但出现上述错误。
错误原因
- 导出解析异常:在Next.js App Router模式下,
"use client"指令的位置或格式问题可能导致Webpack无法正确识别默认导出。若指令与后续代码之间存在多余空行,打包工具可能无法正确标记客户端组件,进而导致导出失效。 - 初始值逻辑错误:Hook中
useState的初始值将width错误设置为window.innerHeight,虽非报错直接原因,但会导致宽高颠倒,影响最终显示效果。
解决步骤
1. 修复导出识别问题
- 调整指令格式:确保
"use client"位于文件最顶部,且与后续代码无多余空行(部分打包工具对指令位置敏感):"use client"; import { useEffect, useState } from "react"; // 剩余代码保持不变 - 改用命名导出:避免默认导出的识别问题,修改Hook文件的导出方式:
组件中对应修改导入:// 替换export default为命名导出 export const useWindowsDimension = (): { width: number; height: number } => { // 函数体逻辑不变 };import { useWindowsDimension } from "@/hooks/useWindowsDimension";
2. 修正初始值错误
将useState中的width初始值从window.innerHeight改为window.innerWidth:
const [windowDimension, setWindowDimension] = useState({ width: typeof window !== "undefined" ? window.innerWidth : 0, height: typeof window !== "undefined" ? window.innerHeight : 0, });
更优实现方案
1. 添加防抖优化
减少resize事件触发频率,提升性能:
"use client"; import { useEffect, useState, useCallback } from "react"; export const useWindowsDimension = () => { const [dimensions, setDimensions] = useState({ width: typeof window !== "undefined" ? window.innerWidth : 0, height: typeof window !== "undefined" ? window.innerHeight : 0, }); // 防抖函数,延迟100ms更新 const debouncedResize = useCallback(() => { setDimensions({ width: window.innerWidth, height: window.innerHeight, }); }, []); useEffect(() => { const handleResize = () => { clearTimeout(window.resizeTimeout); window.resizeTimeout = setTimeout(debouncedResize, 100); }; window.addEventListener("resize", handleResize); debouncedResize(); // 初始执行一次 return () => { window.removeEventListener("resize", handleResize); clearTimeout(window.resizeTimeout); }; }, [debouncedResize]); return dimensions; };
2. 支持移动端屏幕方向变化
添加orientationchange事件监听,适配移动端屏幕旋转:
useEffect(() => { const handleResize = () => { clearTimeout(window.resizeTimeout); window.resizeTimeout = setTimeout(debouncedResize, 100); }; window.addEventListener("resize", handleResize); window.addEventListener("orientationchange", handleResize); // 添加方向变化监听 debouncedResize(); return () => { window.removeEventListener("resize", handleResize); window.removeEventListener("orientationchange", handleResize); // 移除监听 clearTimeout(window.resizeTimeout); }; }, [debouncedResize]);
3. 优化SSR兼容性
若需在服务端渲染时提供合理初始值,可保留typeof window !== "undefined"的判断,确保服务端不会执行客户端API,避免渲染报错。
内容的提问来源于stack exchange,提问作者bisht_xp
相关产品推荐
相关产品推荐

