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

将redux thunk传入自定义hook时useEffect依赖缺失问题如何解决

问题根因

你遇到的重复请求问题核心是:在SomeListing组件每次渲染时,都会执行fetchPropertyByUserId({userId: userId, page: page})生成一个全新的thunk实例,哪怕传入的参数没有变化,生成的对象引用也会更新。如果直接将dispatchAction加入useEffect依赖数组,每次渲染都会触发effect执行,自然会反复发起请求。


方案1:调整自定义Hook传参结构(更推荐)

调整useFetchData的入参规则,不再直接传入生成好的thunk实例,而是传入thunk创建函数和请求参数,从根源保证依赖的稳定性。

修改后的自定义Hook代码

const useFetchData = (createDispatchAction, params) => {
  const dispatch = useDispatch();
  const [loadMoreLoading, setLoadMoreLoading] = useState(false);
  const [errorMsg, setErrorMsg] = useState();

  useEffect(() => {
    const fetchData = async () => {
      setLoadMoreLoading(true);
      // 内部生成thunk实例
      const dispatchAction = createDispatchAction(params);
      const resultAction = await dispatch(dispatchAction);
      if (resultAction.meta.requestStatus === 'rejected') {
        setErrorMsg(resultAction.payload.message);
      }
      setLoadMoreLoading(false);
    };
    fetchData();
  }, [dispatch, createDispatchAction, params]);

  return [loadMoreLoading, errorMsg];
};

修改后的组件调用代码

const SomeListing = ({userId}) => {
  const [page, setPage] = useState(1);
  // 用useMemo稳定参数引用,只有userId、page变化时才生成新的参数对象
  const fetchParams = useMemo(() => ({
    userId,
    page
  }), [userId, page]);

  const [loadMoreLoading, errorMsg] = useFetchData(
    fetchPropertyByUserId, // 直接传入顶层定义的thunk创建函数,引用永久稳定
    fetchParams
  );
};

这个方案完全符合React的依赖声明规范,不需要额外跳过eslint检查,只有当userId或page变化时才会重新发起请求,完全匹配需求。

方案2:用useRef缓存thunk实例(改造成本更低)

如果不想调整现有传参逻辑,可以用useRef缓存最新的dispatchAction,避开对动态生成的thunk实例的依赖声明。

修改后的自定义Hook代码

const useFetchData = (dispatchAction, page) => {
  const dispatch = useDispatch();
  const [loadMoreLoading, setLoadMoreLoading] = useState(false);
  const [errorMsg, setErrorMsg] = useState();
  // 用ref存储最新的dispatchAction实例
  const latestDispatchAction = useRef(dispatchAction);

  // 单独维护ref更新,dispatchAction变化时自动同步到ref
  useEffect(() => {
    latestDispatchAction.current = dispatchAction;
  }, [dispatchAction]);

  useEffect(() => {
    const fetchData = async () => {
      setLoadMoreLoading(true);
      // 从ref中读取最新的实例执行
      const resultAction = await dispatch(latestDispatchAction.current);
      if (resultAction.meta.requestStatus === 'rejected') {
        setErrorMsg(resultAction.payload.message);
      }
      setLoadMoreLoading(false);
    };
    fetchData();
  }, [dispatch, page]);

  return [loadMoreLoading, errorMsg];
};

这个方案不需要修改上层组件的调用代码,也不会触发eslint的依赖警告,同样可以实现只有page变化时才发起请求的逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 22:36:09