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

react-hooks-testing-library测试中StoreProvider更新未包裹act()报错解决

解决React测试中StoreProvider更新未包裹act的警告

问题根源

测试过程中,异步请求完成后触发的StoreProvider状态更新,没有被React测试的act()上下文包裹。React要求所有会导致组件/hook状态变更的操作,都要在act中执行,否则会抛出这个警告。

具体修复方案

1. 测试中等待异步流程完成

使用@testing-library/react提供的waitFor或renderHook返回的waitForNextUpdate方法,确保异步请求和后续的store更新都被React跟踪到。

示例测试代码:

import { renderHook, waitFor } from '@testing-library/react';
import { StoreProvider } from './StoreProvider';
import useUserSearch from './useUserSearch';
import axios from 'axios';

test('useUserSearch 成功获取用户并更新store', async () => {
  // 模拟axios请求,避免真实网络调用
  jest.spyOn(axios, 'get').mockResolvedValue({ data: [{ id: 1, name: '测试用户' }] });

  const { result } = renderHook(() => useUserSearch(), {
    wrapper: StoreProvider, // 确保hook处于StoreProvider上下文内
  });

  // 等待异步请求完成及store更新
  await waitFor(() => {
    // 这里添加你的断言,比如验证store中的用户数据已更新
    expect(result.current.someState).toBe('预期值');
  });

  // 清理mock,避免影响其他测试
  axios.get.mockRestore();
});

2. 修正自定义hook的实现

确保异步操作在useEffect内部执行,且不要直接将useEffect回调设为async函数(因为useEffect期望返回清理函数或undefined,async函数会返回Promise,可能导致异常)。

正确的useUserSearch实现:

import { useEffect } from 'react';
import { useStoreDispatch } from './StoreProvider';
import fetchUsers from './fetchUsers';

export default function useUserSearch() {
  const dispatch = useStoreDispatch();

  useEffect(() => {
    const fetchAndUpdateStore = async () => {
      const users = await fetchUsers();
      dispatch({ type: 'SET_USERS', payload: users });
    };

    fetchAndUpdateStore();
  }, [dispatch]);

  // 返回需要暴露的状态或方法
  return { /* ... */ };
}

3. 检查StoreProvider的状态更新逻辑

确保StoreProvider使用React原生的状态管理API(useState或useReducer)来更新状态,不要直接修改状态对象:

import { createContext, useContext, useReducer } from 'react';

const StoreContext = createContext();

const initialState = { users: [] };

function storeReducer(state, action) {
  switch (action.type) {
    case 'SET_USERS':
      return { ...state, users: action.payload };
    default:
      return state;
  }
}

export function StoreProvider({ children }) {
  const [state, dispatch] = useReducer(storeReducer, initialState);
  return (
    <StoreContext.Provider value={{ state, dispatch }}>
      {children}
    </StoreContext.Provider>
  );
}

export const useStoreDispatch = () => useContext(StoreContext).dispatch;
export const useStoreState = () => useContext(StoreContext).state;

避坑指南

  • 不要在useEffect回调中直接写async函数,必须在内部定义async函数后调用。
  • 测试时绝不能跳过等待异步操作完成的步骤,否则异步更新会在测试结束后执行,触发警告。
  • 模拟axios请求时,确保mock的返回值是正确的resolved Promise,避免出现未处理的rejection。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:35:32