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

useLocation无法检测MemoryRouter路由变化?测试问题求助

问题原因

当你使用screen.rerender重新渲染MemoryRouter时,尽管传入了新的initialEntries,但MemoryRouter在初始化时创建的history实例不会随props变化而重置。这导致路由上下文始终保持第一次渲染时的状态(/?name=Banana),所以useLocation或useSearchParams获取到的还是旧的查询参数,最终组件显示Banana is red。

解决方案

方案1:手动控制history实例

通过createMemoryHistory创建可手动操作的history对象,直接更新路由状态,再配合重新渲染更新组件props:

import { render, screen } from '@testing-library/react';
import { Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import Module from './Module';

test('Module responses to both prop change and query param change', () => {
  // 初始化history实例
  const history = createMemoryHistory({
    initialEntries: ["/?name=Banana"]
  });

  render(
    <Router location={history.location} navigator={history}>
      <Module color="yellow" />
    </Router>
  );

  expect(screen.getByText('Banana is yellow')).toBeInTheDocument();

  // 更新路由查询参数
  history.replace("/?name=Apple");
  // 重新渲染组件并更新props
  render(
    <Router location={history.location} navigator={history}>
      <Module color="red" />
    </Router>
  );

  expect(screen.getByText('Apple is red')).toBeInTheDocument();
});

方案2:卸载后重新渲染

如果坚持使用MemoryRouter,可以先卸载原有组件,再重新渲染新的MemoryRouter实例:

import { render, screen, unmountComponentAtNode } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import Module from './Module';

test('Module responses to both prop change and query param change', () => {
  const container = document.createElement('div');
  document.body.appendChild(container);

  // 第一次渲染
  render(
    <MemoryRouter initialEntries={["/?name=Banana"]}>
      <Module color="yellow" />
    </MemoryRouter>,
    { container }
  );

  expect(screen.getByText('Banana is yellow')).toBeInTheDocument();

  // 卸载组件
  unmountComponentAtNode(container);

  // 重新渲染新的路由和组件
  render(
    <MemoryRouter initialEntries={["/?name=Apple"]}>
      <Module color="red" />
    </MemoryRouter>,
    { container }
  );

  expect(screen.getByText('Apple is red')).toBeInTheDocument();

  // 清理
  document.body.removeChild(container);
});
为什么之前的尝试无效
  • 使用Routes和Route:问题核心是MemoryRouter的history状态未更新,和路由嵌套结构无关,因此添加Routes无法解决。
  • 替换为useSearchParams:useSearchParams同样依赖路由上下文的history状态,只要history未更新,就无法获取新参数。
  • 修改initialEntries:MemoryRouter的initialEntries仅在组件初始化时生效,后续props变化不会重置已创建的history实例状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 22:31:15