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

测试时React状态更新未触发重渲染,Material UI开关状态不同步问题

问题根因

  1. 等待逻辑不可靠:setTimeout(resolve, 0)仅能清空当前宏任务队列,无法覆盖Apollo Client mutation执行、缓存更新、React重渲染的全链路异步流程,断言执行时组件往往还未完成状态更新。
  2. Apollo缓存未同步:默认情况下Apollo Client不会自动将mutation返回的结果同步到原有query的缓存中,组件从query获取的callbackEnabled始终为初始的true,因此不会触发重渲染更新开关状态。本地运行正常通常是因为生产逻辑中触发了query重取、或者配置了缓存更新规则,测试环境仅存在mock请求因此无法触发对应逻辑。
  3. 冗余的act包裹:react-testing-library的render、userEvent.click等API已经内置了act处理,额外嵌套act反而可能导致状态更新捕获异常。

修复方案

1. 组件侧补全mutation缓存更新逻辑

在组件调用useMutation时新增update配置,手动将mutation返回的最新值同步到对应query的缓存中:

const [updateCallbackStatus] = useMutation(myMutation, {
  update(cache, { data: { myMutation } }) {
    cache.writeQuery({
      query: myQuery,
      variables: { clientId: 'cl_0' },
      data: {
        myQuery: {
          // 如果组件逻辑开启了typename则补充对应类型字段,否则可省略
          callbackEnabled: myMutation.callbackEnabled
        }
      }
    })
  }
})

2. 测试代码替换不可靠的延时逻辑

使用react-testing-library提供的findBy*查询和waitFor工具等待状态更新,无需手动设置延时:

it('should update boolean field', async () => {
  const mocks = [
    {
      request: {
        query: myQuery,
        variables: {
          clientId: 'cl_0',
        },
      },
      result: {
        data: {
          myQuery: {
            callbackEnabled: true
          },
        },
      },
    },
    {
      request: {
        query: myMutation,
        variables: {
          clientId: 'cl_0',
          callbackEnabled: false,
        },
      },
      result: {
        data: {
          myMutation: {
            callbackEnabled: false,
          },
        },
      },
    },
  ];

  render(
    <MockedProvider mocks={mocks} addTypename={false}>
      <MyComponent clientId="cl_0" error={undefined} />
    </MockedProvider>
  );

  // 等待初始查询完成,验证初始状态
  const callbackSwitch = await screen.findByRole('checkbox', { name: /callbacks/i });
  expect(callbackSwitch).toBeChecked();

  // 模拟点击开关
  userEvent.click(callbackSwitch);

  // 等待开关状态更新完成后断言
  await waitFor(() => {
    expect(screen.getByRole('checkbox', { name: /callbacks/i })).not.toBeChecked();
  });
});

常见疑问

不需要手动强制触发组件重渲染,当前问题本质是组件依赖的状态(Apollo查询结果)未发生变化,因此不会触发重渲染,补全缓存更新逻辑后即可正常触发重渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 19:27:03