如何在 React-query 中使用惰性查询?

web*_*ber 15 javascript reactjs react-query

我正在使用 React-query 进行 API 调用。我想知道是否有一种方法可以以惰性方式调用查询。

意味着仅当查询参数更改时才调用查询。

这就是我目前所拥有的;我正在使用一个 hack,其中useEffectifrecipeName更改,然后运行该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`
  );
};
Run Code Online (Sandbox Code Playgroud)
  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);
  };
Run Code Online (Sandbox Code Playgroud)

最好,我想在函数中调用查询handleOnSearchSubmit

我可以创建一个自定义useLazyQuery钩子来处理这个问题,但我想知道 React-query 是否有本地方法来处理这个问题。

TkD*_*odo 14

最好,我想在“handleOnSearchSubmit”函数中调用查询。

这是一种非常必要的思考方式,但反应查询更具声明性。您没有指定:“当我单击该按钮时,我想要获取”,但您只是说:“这些是我需要的输入”,并且只要这些输入发生变化,react-query就会重新获取。

所以你要做的就是把查询运行所需的东西放入查询键中,这样react-query

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

然后,你需要做的就是调用setRecipeNamehandleOnSearchSubmitreact-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
  }
])
Run Code Online (Sandbox Code Playgroud)

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

  • 如果您想要一个提交表单的按钮,最好“提升状态”:拥有查询所依赖的更全局的状态,以及表单的一些本地状态。一旦用户点击“提交”,您就将用户选择保存在较高的状态中,这将触发查询。我喜欢使用 url 来实现这一点,我在这里有一个完整的codesandbox 示例。在该示例中,实际的表单状态不受控制,但您也可以使用状态或表单库来实现该目的

  • 感谢 TKDodo 的详尽回答。遗憾的是 React-query 没有像 Apollo 客户端那样原生的 useLazyQuery。我会尝试一下 (2认同)