
推荐使用 MemoryRouter 提供真实路由上下文来测试 useParams,而非直接 mock 钩子——这能确保参数解析逻辑与运行时一致,避免因手动 mock 导致的空对象问题。
推荐使用 `memoryrouter` 提供真实路由上下文来测试 `useparams`,而非直接 mock 钩子——这能确保参数解析逻辑与运行时一致,避免因手动 mock 导致的空对象问题。
在 Vitest 中直接 mock react-router-dom 的 useParams 钩子(如通过 vi.mock(...).mockReturnValue(...))往往失效,根本原因在于:useParams 依赖于 Router 提供的上下文(RouterContext)。若组件未被包裹在有效的路由上下文中,useParams 将回退到默认实现并返回空对象 {}——这正是你看到 console.log('useParams:', params) 输出 {} 的原因。
正确的做法是模拟真实的路由环境,让 useParams 在标准上下文中自然工作。react-router-dom 官方推荐且最可靠的方案是使用 MemoryRouter(配合 Routes/Route)为测试提供可控的 URL 和参数解析。
以下是推荐的完整测试写法:
import { render } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
import MyComponent from './Component';
describe('MyComponent', () => {
it('should correctly access the "id" parameter from the route', () => {
// 模拟访问路径 /test/123 → 匹配 /test/:id,自动注入 { id: '123' }
const { container } = render(
<memoryrouter initialentries="{['/test/123']}"><routes><route path="/test/:id" element="{<MyComponent"></route>} />
</routes></memoryrouter>
);
// 此时组件内的 useParams() 将返回 { id: '123' }
// 可进一步断言渲染内容,例如:
// expect(container.querySelector('div')).toHaveTextContent('ID: 123');
});
});
✅ 关键要点说明:
- initialEntries 指定初始 URL 路径(必须是数组格式);
- Route 的 path 必须包含动态段(如 :id),且与实际路由配置一致;
- element 直接传入待测组件,无需额外包装或 props 注入;
- 此方式完全复现了生产环境行为,无需维护 mock 实现,也避免了 vi.mock 作用域、模块缓存等陷阱。
⚠️ 注意事项:
- 不要混合使用 vi.mock('react-router-dom') 和 MemoryRouter —— 前者会破坏上下文链路,导致 useParams 无法读取真实参数;
- 若组件还依赖 useNavigate 或 useLocation,同样适用该方案,无需额外 mock;
- 对于嵌套路由场景,可嵌套 Routes 和 Route,或使用 createMemoryRouter(v6.4+)进行更精细控制。
总结:测试应尽量贴近运行时环境。用 MemoryRouter 构建轻量、隔离、可预测的路由上下文,不仅解决了 useParams 返回空对象的问题,也让测试更健壮、可维护,并与 react-router-dom 的设计哲学保持一致。











