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

解决自定义Hook重复执行问题:基于createAsyncThunk的数据请求

问题分析与解决方案

你的自定义Hook执行两次的核心原因有两个:一是没有用useEffect包裹异步请求逻辑,导致组件每次渲染都会触发请求;二是React 18的严格模式在开发环境会自动执行两次挂载逻辑,用来检测潜在的副作用问题。

下面是具体的修复方案:

1. 重构自定义Hook(正确写法)

将异步请求逻辑放入useEffect中,用useState管理数据、加载状态和错误信息,符合React Hook的规则:

import { useDispatch } from 'react-redux';
import { useEffect, useState } from 'react';
import { AppDispatch } from '../store'; // 替换为你的store类型路径
import fetchTransactionsHistory from '../features/transactions/transactionSlice'; // 替换为你的thunk路径

export default function useFetchTransactionHistory() {
  const dispatch = useDispatch<AppDispatch>();
  const [data, setData] = useState<any>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    // 标志位:防止组件卸载或重复渲染时更新状态
    let isMounted = true;

    const fetchData = async () => {
      try {
        setIsLoading(true);
        // 使用unwrap()解析createAsyncThunk的返回值:成功时取数据,失败时抛出错误
        const res = await dispatch(fetchTransactionsHistory()).unwrap();
        if (isMounted && res.code === 200) {
          setData(res.data);
        }
      } catch (err) {
        if (isMounted) {
          setError(err as Error);
          console.error(err);
        }
      } finally {
        if (isMounted) {
          setIsLoading(false);
        }
      }
    };

    fetchData();

    // 组件卸载时重置标志位
    return () => {
      isMounted = false;
    };
  }, [dispatch]); // dispatch是Redux提供的稳定函数,可安全作为依赖项

  return { data, isLoading, error };
}

2. 组件中正常使用Hook

export default function TransactionHistory() {
  const { data, isLoading } = useFetchTransactionHistory(); 

  if (isLoading) return <div>加载中...</div>;

  return(
    <div>{data ? JSON.stringify(data) : '暂无交易记录'}</div>
  );
}

关键说明

  • useEffect的作用:确保请求只在组件挂载时执行一次,后续组件重新渲染不会重复触发请求。
  • unwrap()方法:createAsyncThunk返回的Promise包含Redux的action信息,unwrap()可以直接获取API返回的原始数据,或在请求失败时抛出错误,方便统一处理。
  • 严格模式的两次渲染:React 18开发环境的两次挂载是调试机制,生产环境不会触发。如果要避免开发环境的重复状态更新,可以用上述代码中的isMounted标志位过滤无效操作,但请求本身还是会发两次(这是严格模式的特性,无需强行阻止)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 11:55:23