javascript 如何将Lazy查询与React-query结合使用?

ljo96ir5  于 2023-03-16  发布在  Java
关注(0)|答案(4)|浏览(217)

我正在使用React-query进行API调用。我想知道是否有一种方法可以用一种懒惰的方式调用查询。
表示仅当查询参数更改时调用查询。
这是我目前拥有的;我正在使用一个带有“useEffect”的hack,如果recipeName发生变化,则运行refetch函数。

export const searchRecipeByName = async (recipeName: string) => {
  return await api.get(
    `/recipes/complexSearch?apiKey=${process.env.NEXT_PUBLIC_SPOONACULAR_API_KEY}&query=${recipeName}&addRecipeInformation=true&fillIngredients=true`
  );
};
const [recipeName, setRecipeName] = useState("");

  const { data, refetch } = useQuery(
    "homePageSearchQuery",
    () => searchRecipeByName(recipeName),
    { enabled: false }
  );

// HACK
  useEffect(() => {
    if (!!recipeName) {
      refetch();
    }
  }, [recipeName]);

  const handleOnSearchSubmit = async (recipeSearch: RecipeSearch) => {
    setRecipeName(recipeSearch.search);
  };

我最好在“handleOnSearchSubmit”函数中调用查询。
我可以创建一个定制的useLazyQuery钩子来处理这个问题,但是我想知道React-query是否有一个本地的方法来处理这个问题。

unhi4e5o

unhi4e5o1#

我最好在“handleOnSearchSubmit”函数中调用查询。
这是一种非常命令式的思考方式,但是react-query更像是声明式的,你不需要指定:“当我点击那个按钮时,我想获取”,但你只是说:“这些是我需要的输入”,并且只要这些输入改变,react-query就会重新获取。
因此,您要做的是将查询运行所需的内容 * 放入 * 查询键中,以便react-query

  • 为每个依赖项单独缓存
  • 只要依赖项未就绪,就可以禁用它
const [recipeName, setRecipeName] = React.useState('')
const { isLoading, data } = useQuery(
  ['homePageSearchQuery', recipeName],
  () => searchRecipeByName(recipeName),
  {
    enabled: !!recipeName
  }
])

然后,您需要做的就是在handleOnSearchSubmit中调用setRecipeName,react-query将执行查询。
还有一些你可能需要考虑的事情:

  • 如果要避免recipeName更改之间的硬加载状态,请设置keepPreviousData: true
  • 上面的代码在每次recipeName发生变化时都会运行一个查询。如果在单击按钮时没有发生这种情况,而是说每当用户在输入字段中键入内容时,您都需要对它进行反跳。对于这些情况,请考虑useDebounce
const [recipeName, setRecipeName] = React.useState('')
const debouncedRecipeName = useDebounce(recipeName, 1000)
const { isLoading, data } = useQuery(
  ['homePageSearchQuery', debouncedRecipeName],
  () => searchRecipeByName(debouncedRecipeName),
  {
    enabled: !!debouncedRecipeName
  }
])

这将允许您输入数据并将其显示在文本字段中,但仅在1秒不活动后创建一个新的缓存条目/触发一个新请求。

  • 如果您希望有一个提交表单的按钮,最好使用“lift state up”:有一个查询所依赖的全局状态,以及一些表单的本地状态。一旦用户点击“submit”,您将用户选择保存在更高级别的状态中,这将触发查询。我喜欢使用url来实现这一点,并且我有一个完整的codesandbox example here。在该示例中,实际的表单状态是不受控制的,但您也可以使用state或formlib来实现这一点
wz1wpwve

wz1wpwve2#

您可以使用这个Wrapper钩子在react-query中创建useLazyQuery

import { useCallback, useState } from 'react';
import {
  QueryFunction,
  QueryKey,
  useQuery,
  UseQueryOptions,
  UseQueryResult,
} from 'react-query';

type UseQueryParams = Parameters<typeof useQuery>;

export default function useLazyQuery<TData, TError>(
  key: UseQueryParams[0],
  fetchFn: QueryFunction<TData, QueryKey>,
  options?: Omit<UseQueryOptions<TData, TError, unknown, QueryKey>, 'queryKey' | 'queryFn'>
): [() => void, UseQueryResult<unknown, unknown>] {
  const [enabled, setEnabled] = useState(false);

  const query = useQuery<TData, TError, unknown, QueryKey>(key, fetchFn, {
    ...(options || {}),
    enabled,
  });

  const trigger = useCallback(() => {
    if (!enabled) {
      setEnabled(true);
    }
  }, [fetchFn, enabled]);

  return [trigger, query];
}
bvjxkvbb

bvjxkvbb3#

像这样做

const { isLoading, data } = useQuery([
    'homePageSearchQuery',
    {recipeName}],
    () => searchRecipeByName(recipeName), {}
);

每当recipeName的值发生更改时,它都会运行查询。

vbkedwbf

vbkedwbf4#

惰性查询可以通过以下方式实现:

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

export const useGetRecipeByNameLazy = () => {
  const queryClient = useQueryClient();
  return (recipeName: string) => queryClient.ensureQueryData({
    queryKey: ['homePageSearchQuery', recipeName],
    queryFn: () => searchRecipeByName(recipeName),
  });
};

使用方法:

const getRecipeByName = useGetRecipeByNameLazy();

const handleSearch = async (recipeName: string) => {
    const recipe = await getRecipeByName(recipeName);
    console.log(recipe);
}

相关问题