You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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立即占满整个屏幕,但出现上述错误。

错误原因

  1. 导出解析异常:在Next.js App Router模式下,"use client"指令的位置或格式问题可能导致Webpack无法正确识别默认导出。若指令与后续代码之间存在多余空行,打包工具可能无法正确标记客户端组件,进而导致导出失效。
  2. 初始值逻辑错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 05:07:21