使用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
相关产品推荐
相关产品推荐

