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

测试自定义Hook时window未定义引发TypeError的解决方法

解决方法

首先,你的useMediaQuery Hook存在一个潜在问题:在useEffect中直接访问window.matchMedia,但未检查window是否存在。这会导致在服务端渲染或window未定义的环境中直接抛出错误,先修复这个问题:

import React from "react";
import isWindowDefined from "../isWindowDefined";

// 注意:你重复定义了isWindowDefined,建议删除本地定义,直接使用导入的版本
// export const isWindowDefined = () => window !== undefined;

const useMediaQuery = (query: string): boolean => {
  const getMatches = (query: string): boolean => {
    if (isWindowDefined()) {
      return window.matchMedia(query).matches;
    }
    return false;
  };

  const [matches, setMatches] = React.useState<boolean>(getMatches(query));

  const handleChange = () => {
    setMatches(getMatches(query));
  };

  React.useEffect(() => {
    // 添加window存在性检查
    if (!isWindowDefined()) return;

    const matchMedia = window.matchMedia(query);
    handleChange();

    matchMedia.addEventListener("change", handleChange);

    return () => {
      matchMedia.removeEventListener("change", handleChange);
    };
  }, [query]);

  return matches;
};

export default useMediaQuery;

接下来,针对window未定义的测试场景,不要直接全局设置window = undefined——这会破坏react-test-renderer内部对window的依赖。更好的方式是模拟isWindowDefined函数返回false,让Hook认为window不存在,但实际保留window供测试库使用。

测试代码示例

假设你的isWindowDefined是单独的模块:

import React from 'react';
import { renderHook } from '@testing-library/react-hooks';
import useMediaQuery from './useMediaQuery';
import isWindowDefined from '../isWindowDefined';

// 模拟isWindowDefined返回false
jest.mock('../isWindowDefined', () => () => false);

test('当window未定义时返回false', () => {
  const { result } = renderHook(() => useMediaQuery('(min-width: 768px)'));
  
  expect(result.current).toBe(false);
});

如果isWindowDefined是在useMediaQuery文件内部定义的,调整mock方式:

import React from 'react';
import { renderHook } from '@testing-library/react-hooks';
import * as useMediaQueryModule from './useMediaQuery';

// 模拟内部的isWindowDefined函数
jest.spyOn(useMediaQueryModule, 'isWindowDefined').mockReturnValue(false);

test('当window未定义时返回false', () => {
  const { result } = renderHook(() => useMediaQueryModule.default('(min-width: 768px)'));
  
  expect(result.current).toBe(false);
});

为什么不直接mock window?

如果强行全局设置window = undefined,react-test-renderer在执行时会尝试访问window.event等属性,导致抛出你遇到的TypeError。通过模拟isWindowDefined,我们既能验证Hook的 fallback 逻辑,又不会干扰测试库的正常运行。

内容的提问来源于stack exchange,提问作者karvai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 11:00:13