@tanstack/react-query@5.35.5

1. isPending isLoading isFetching 傻傻分不清

  const { data: knowledgeList, isFetching: loading } = useQuery({
    queryKey: ['knowledgeList'],
    initialData: [],
    gcTime: 0,
  });

useQuery的isFetching是接口在请求中

React Query 5: When to use isLoading, isFetching, and isRefetching

2. 单独获取一个接口的loading状态

useQuery()会返回isFetching,但是往往component是分开写的,就是发起请求在一个component,而Spin在另一个component,这时候就需要独立的拿到isFetching

import {
  useIsFetching,
} from '@tanstack/react-query';

export const useKnowledgeDetailIsFetching = () => {
  return useIsFetching({ queryKey: ['knowledgeDetail'] }) > 0;
};

注意:useIsFetching()返回的是数字

Background Fetching Indicators

同理,对于useMutation

export const useChunkIsTesting = () => {
  return useIsMutating({ mutationKey: ['testChunk'] }) > 0;
};

3. queryClient.getQueryData与useQuery获取共享数据的区别

比如页面加载的时候使用useQuery请求到了数据,被@tanstack/react-query缓存了起来,在其他组件里想拿到该数据,通常会直接调用useQuery获取数据,但是在项目里出了问题,如下图,我在两个节点拖拽无法建立连线,因为线跟后端返回的数据是管理的,边节点里面调用了useQuery,每次有新线连接就会调用useQuery,这样导致我客户端的数据被接口返回的数据所覆盖,从而连接不成功。根本原因在于retryOnMount参数为true,在每次挂载组件时自动触发重新获取。
image.png
queryClient.getQueryData就不会在拖线的时候发送请求了

  const queryClient = useQueryClient();
  const flowDetail = queryClient.getQueryData<IFlow>(['flowDetail']);

4. 在不同组件共享useMutation获取的数据

通常都是用useQuery去获取代get方法的接口的数据的,但是有时候后端给的接口是post,需要提交表单数据,这个时候需要用button触发接口的调用,如果用useQuery的话,需要使用enabled:false禁用useQuery的默认加载调用的行为,然后结合refetch函数去手动调用,但是refetch不能传递参数,需要将参数传到state或者redux、zustand等状态管理库托管,所以还是用useMutation方便点,但是怎么在不同组件共享useMutation获取的数据?

export const useSelectTestingResult = (): ITestingResult => {
  const data = useMutationState({
    filters: { mutationKey: ['testChunk'] },
    select: (mutation) => {
      return mutation.state.data;
    },
  });
  return (data.at(-1) ?? { // 获取接口返回的最新的一条数据
    chunks: [],
    documents: [],
    total: 0,
  }) as ITestingResult;
};

5. 模糊匹配useQuery缓存的数据

列表页面往往有很多查询条件,比如分页,搜索,排序等,@tanstack/react-query@5.35.5推荐将查询条件写进queryKey作为依赖,从而触发接口的重新请求,但是我们在不同的组件希望拿到被@tanstack/react-query@5.35.5缓存的数组,而不是层层传递,useQuery代码如下,
image.png
如果在不同的组件里使用useFetchNextChunkList,如果有组件mount,则useFetchNextChunkList会被多次执行,会导致每次的查询条件都是初始值,因为useState会被重新执行,所以只好选择 getQueriesData, Share state between components #2310 这种方式行不通

export const useSelectChunkList = () => {
  const queryClient = useQueryClient();
  const data = queryClient.getQueriesData<{
    data: IChunk[];
    total: number;
    documentInfo: IKnowledgeFile;
  }>({ queryKey: ['fetchChunkList'] });

  return data[0][1];
};

6. 缓存全局数据

Using react-query to store global state? #2852

7. 在发出请求到拿到数据中间会返回初始值initialData

我想保留之前的查询结果,会导致组件无效的rerender,即使用了placeholderData: keepPreviousData也不行。有待讨论

f20d206dd4bb04a1bdee6861d0aca6b.png

8. 自定义staleTime: 20 * 1000,设置initialData跟不设置该值有不同的表现

阅读了 React Query as a State Manager 自己做了如下测试
demo.tsx

import { useFetchFlowTemplates } from '@/hooks/flow-hooks';

const Inner = () => {
  const ret = useFetchFlowTemplates();
  const data = ret?.data;
  return <ul>{data?.map((x) => <li key={x.id}>{x.title}</li>)}</ul>;
};

const Demo = () => {
  const ret = useFetchFlowTemplates();
  const data = ret?.data;

  return (
    <section>
      <h6>{data?.length}</h6>
      {data && <Inner></Inner>}
    </section>
  );
};

export default Demo;

hooks

export const useFetchFlowTemplates = (): ResponseType<IFlowTemplate[]> => {
  const { data } = useQuery({
    queryKey: ['fetchFlowTemplates'],
    staleTime: 20 * 1000,
    initialData: [],
    queryFn: async () => {
      const { data } = await flowService.listTemplates();
      return data;
    },
  });

  return data;
};

上述代码不会发送请求,将initialData注释掉,如下,可以正常发送一条请求,有待进一步探究

export const useFetchFlowTemplates = (): ResponseType<IFlowTemplate[]> => {
  const { data } = useQuery({
    queryKey: ['fetchFlowTemplates'],
    staleTime: 20 * 1000,
    // initialData: [],
    queryFn: async () => {
      const { data } = await flowService.listTemplates();
      return data;
    },
  });

  return data;
};

assassin_cike
1.3k 声望74 粉丝

生活不是得过且过


« 上一篇
react 继续踩坑
下一篇 »
SSE post 实践