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

使用RTL测试含useContext钩子的组件时遇解构错误

问题:React Testing Library测试useContext组件时解构null报错

我尝试用React Testing Library(RTL)测试一个使用useContext钩子的组件,编写了如下测试代码:

const CurrentViewContext = createContext('');
test('Renders the texts: My Services', () => {
  render(
    <CurrentViewContext.Provider
      value={{
        setCurrentView: jest.fn(),
        setViewData: jest.fn(),
      }}
    >
      <MyServices />,
    </CurrentViewContext.Provider>,
  );
})

组件代码片段:

import { useState, useEffect, useContext } from 'react';    
const MyServicesListView: React.FC<MyServicesListViewProps> = ({ searching }) => {
  const { setCurrentView, setViewData } = useContext(CurrentViewContext);
  /* 省略其他代码 */
}

运行测试时出现错误:

TypeError: Cannot destructure property 'setCurrentView' of '(0 , _react.useContext)(...)' as it is null.

      19 |
      20 | const MyServicesListView: React.FC<MyServicesListViewProps> = ({ searching }) => {
    > 21 |   const { setCurrentView, setViewData } = useContext(CurrentViewContext);

实际项目中,CurrentViewContext在index.tsx中创建并导出:

export const CurrentViewContext = createContext(null);

const MyservicesIndex: FC<Props> = () => {
  const [currentView, setCurrentView] = useState('Home');
  const [viewData, setViewData] = useState({});

  const renderComponent = () => {
    switch (currentView) {
      case 'Home':
        return <MyServices />;
      case 'PrivateApi':
        return <PrivateApiServices />;
      case 'DataMesh':
        return (
          <>
            <DataMeshServices />
            <CatalogFooter />
          </>
        );
      case 'ARR':
        return <MSAlgoRiskReport />;
      default:
        return <MyServices />;
    }
  };

  return (
    <CurrentViewContext.Provider
      value={{
        currentView,
        setCurrentView,
        viewData,
        setViewData,
      }}
    >
      <> {renderComponent()} </>
    </CurrentViewContext.Provider>
  );
};

export default MyservicesIndex;

(MyServices组件会渲染MyServicesListView)

我查阅资料后认为操作正确,但仍报错,请问问题出在哪里?


解决方案

问题核心是测试中创建的Context和组件使用的Context不是同一个实例:

  • 你在测试代码里重新创建了一个CurrentViewContext,但组件里实际导入的是index.tsx中导出的那个Context。这两个Context完全独立,测试时组件的useContext(CurrentViewContext)获取到的是index.tsx中创建Context时的默认值null,导致无法解构报错。

修改测试代码的步骤:

  • 直接从项目的index.tsx导入已有的CurrentViewContext,不要自己重新创建
  • 使用导入的Context包裹测试组件,同时根据组件需求补充完整的value属性

修改后的测试代码:

// 导入项目中已有的Context
import { CurrentViewContext } from './index';

test('Renders the texts: My Services', () => {
  render(
    <CurrentViewContext.Provider
      value={{
        setCurrentView: jest.fn(),
        setViewData: jest.fn(),
        currentView: 'Home',
        viewData: {},
      }}
    >
      <MyServices />
    </CurrentViewContext.Provider>,
  );
  expect(screen.getByText('My Services')).toBeInTheDocument();
})

这样组件就能正确获取到测试中Provider提供的值,不会再出现解构null的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:12:54