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

React Query自定义hook无法在Redux Saga中调用,求解决办法

问题描述

我正将部分无需保留在Redux中的数据从Redux Store迁移至React Query,已将国家数组从Store移至一个通过React Query调用API的自定义hook中。
现在另一个Redux Saga需要使用该国家数组,但无法在Saga中调用hook,触发如下报错:

Error: React Hook "useCountries" is called in function "onSearchInit" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use". react-hooks/rules-of-hooks

我的hook导入方式如下:

import { useCountries } from "@mysite/hooks/useCountries";

使用方式如下:

const { countries } = useCountries();

我对Redux并不精通,请问是否有其他方法可将hook中的数据传入Saga?

解决方案

方法1:抽离独立的请求函数复用逻辑

React Query的hook只是封装了请求+缓存的逻辑,你可以把核心的API请求代码单独抽成独立函数,让Saga直接调用:

  1. 重构useCountries hook,拆分请求逻辑:
// @mysite/hooks/useCountries.js
export const fetchCountries = async () => {
  const res = await fetch('/api/countries'); // 替换为你的实际API地址
  if (!res.ok) throw new Error('获取国家数据失败');
  return res.json();
};

export const useCountries = () => {
  return useQuery({
    queryKey: ['countries'],
    queryFn: fetchCountries,
  });
};
  1. 在Saga中直接调用这个函数:
import { fetchCountries } from "@mysite/hooks/useCountries";
import { call, put } from 'redux-saga/effects';

function* onSearchInit() {
  try {
    const countries = yield call(fetchCountries);
    // 拿到数据后执行后续逻辑,比如存入Store或直接使用
    yield put({ type: 'SEARCH_INIT_SUCCESS', payload: { countries } });
  } catch (err) {
    yield put({ type: 'SEARCH_INIT_FAILED', payload: err.message });
  }
}

⚠️ 注意:这种方式Saga会单独发起请求,不会复用React Query的缓存。如果需要复用缓存,参考其他方法。

方法2:通过React组件同步数据到Redux Store

在已挂载的React组件中(比如根组件或页面组件),用useCountries获取数据后dispatch到Redux Store,Saga再从Store中读取:

  1. 组件中同步数据:
import { useCountries } from "@mysite/hooks/useCountries";
import { useDispatch } from 'react-redux';
import { useEffect } from 'react';

function App() {
  const dispatch = useDispatch();
  const { data: countries } = useCountries();

  useEffect(() => {
    if (countries) {
      dispatch({ type: 'SET_COUNTRIES', payload: countries });
    }
  }, [countries, dispatch]);

  // 组件其他逻辑...
}
  1. Saga中通过select获取Store中的数据:
import { select, put } from 'redux-saga/effects';

function* onSearchInit() {
  const countries = yield select(state => state.global.countries); // 替换为你的实际Store路径
  if (countries) {
    // 执行搜索初始化逻辑
    yield put({ type: 'DO_SEARCH', payload: { countries } });
  }
}

这种方式能复用React Query的缓存,适合不需要实时发起请求的场景。

方法3:直接访问React Query的缓存实例

如果项目中已经全局配置了React Query Client,可以直接在Saga中读取缓存数据:

  1. 确保Query Client全局可访问:
// src/utils/reactQueryClient.js
import { QueryClient } from '@tanstack/react-query';

export const queryClient = new QueryClient();
  1. 在Saga中读取缓存:
import { queryClient } from '../utils/reactQueryClient';
import { call, put } from 'redux-saga/effects';
import { fetchCountries } from "@mysite/hooks/useCountries";

function* onSearchInit() {
  // 先尝试从缓存获取
  let countries = queryClient.getQueryData(['countries']);
  
  if (!countries) {
    // 缓存没有则发起请求,并存入缓存
    countries = yield call(fetchCountries);
    queryClient.setQueryData(['countries'], countries);
  }

  // 使用countries执行后续逻辑
  yield put({ type: 'SEARCH_INIT', payload: { countries } });
}

这种方式兼顾了缓存复用和Saga直接获取数据的需求,适合需要灵活操作缓存的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 10:24:12