通过数据哈希匹配防止 React-Query 中的数据刷新

Prevent data refresh in React-Query by data hash matching

我用 React-Query returns 命中的 API 一组数据和该数据的哈希键,格式如下:

{
orders:[{order1},{order2},....]
dataHash:number
}

我使用此 dataHash 检查 useQuery() 选项中的请求结果是否相等,以便 reach-query 可以轻松地自行比较大数据集,如下所示:

isDataEqual:(oldData, newData)=>oldData?.dataHash === newData.dataHash, //do not refresh page if hashes are equal

API 还有一项功能,如果 dataHash 与请求中的匹配,则允许不发送数据集。在这种情况下,它只有 returns 以下内容:

{
orders:[] //empty array here
dataHash:number
}

但由于我的比较函数只查看 dataHash,因此不会使用新数据,一切都会按预期工作。

我目前遇到的问题是,我似乎无法在 react-query 中找到一种内置方法来保存旧请求中的 dataHash,以便将其作为参数传递到新请求中。理想情况下,我希望看到 react-query 将旧数据传递到请求函数中,这样我就可以自己比较它,但这不是一个选项。

我还发现它将某种元数据对象传递到请求查询中,但我还没有找到针对任何特定请求改变此对象的方法。我错过了什么吗?

  const getOrders = async (metadata:any): Promise<ShowOrdersResponse> => {
    console.log(metadata) //this holds the "meta" object and query keys
   
    const request: ShowOrdersRequest = {
      searchParam: mySearchParam,
      dataHash: 12//dataHash
    };

    const {data} = await secureAxios.post<ShowOrdersResponse>(ApiEndpoints.ShowOrders, request)
    return data;
  }

  const {data} = useQuery<ShowWorkOrdersResponse>(['workorders', mySearchParam], getOrders, {
    cacheTime: 30000,
    refetchInterval: 5000,
    isDataEqual:(oldData, newData)=>oldData?.dataHash === newData.dataHash, //do not refresh page if hashes are equal, this works as charm
    meta:{dataHash:555}  //I am able to pass this "meta" object into the request query, but cannot mutate it
  });

编辑1: 我实施了建议的解决方案,但它仍然没有完全解决问题。目前我正在组件状态中保存从服务器返回的 dataHash,如下所示:

onSuccess: (data) => setDataHash(data?.data.dataHash)

后来我用不同的搜索参数调用 useQuery(),它认为这是一个完全不同的请求,但由于我发送相同的散列,所以我没有得到任何结果。 isDataEqual() returns false 并用空结果更新数据。

我认为我需要能够保存每个请求的 dataHash(从未定义开始)但这意味着 queryFn 需要访问“oldData.data.dataHash”才能发送它。目前我没有看看如何做到这一点。

您 return 来自 queryFn 的任何内容都将被放入查询缓存中,因此可以作为来自 useQuery data return 的内容使用以及 isDataEqual 函数(因为它通过了相同的 data)。所以我会这样做:

const getOrders = async (): Promise<ShowOrdersResponse> => {
   
    const request: ShowOrdersRequest = {
      searchParam: mySearchParam,
      dataHash: 12
    };

    const { data } = await secureAxios.post<ShowOrdersResponse>(ApiEndpoints.ShowOrders, request)
    return {
      data,
      dataHash
    }
  }

useQuery(
  ['workorders', mySearchParam],
  getOrders,
  {
    isDataEqual:(oldData, newData) => oldData?.dataHash === newData.dataHash,
  }
)

当然,一个缺点是您需要在您的组件中解包 data.data,但您可以使用 select 函数解决这个问题:

useQuery(
  ['workorders', mySearchParam],
  getOrders,
  {
    isDataEqual:(oldData, newData) => oldData?.dataHash === newData.dataHash,
    select: data => data.data
  }
)

这是有效的,因为 isDataEqual 直接从缓存中传递数据,而每个组件(观察者)在 运行 到 select 之后传递数据。所以基本上,你只会传递 dataHash 以便你可以在 isDataEqual.

中使用它