TanStack Query v5自定义搜索Hook:如何使返回数据类型仅为T
解决data类型为T的方法
方法1:使用throwOnError + 类型断言
通过配置throwOnError: true让请求失败时自动抛出错误,结合类型断言确保data类型为T,同时处理加载状态避免初始崩溃:
import { useState } from "react" import { useQuery } from "@tanstack/react-query" type QueryFn<T> = () => Promise<T> export const useSearchList = <T>(initialValue = "", queryFn: QueryFn<T>) => { const [keyword, setKeyword] = useState(initialValue) const onSearch = (value: string) => { const trimmedValue = value.trim() if (trimmedValue.length === 0) { setKeyword("") return } setKeyword(trimmedValue) } const { data, error, isLoading } = useQuery({ queryKey: ["search", keyword], queryFn, enabled: keyword.length > 0, throwOnError: true, // 请求失败时自动抛出错误 }) // 仅当查询已触发(keyword有效)且加载完成但无数据时抛出错误 if (keyword.length > 0 && !isLoading && data === undefined) { throw new Error("搜索未返回任何数据") } // 断言data为T,已通过throwOnError和条件判断确保运行时data存在(或已抛出错误) return { data: data as T, onSearch, isLoading } }
方法2:使用useSuspenseQuery
利用React Suspense机制,组件在数据加载时挂起,此时useSuspenseQuery返回的data类型天然为T(无需处理undefined):
import { useState } from "react" import { useSuspenseQuery } from "@tanstack/react-query" type QueryFn<T> = () => Promise<T> export const useSearchList = <T>(initialValue = "", queryFn: QueryFn<T>) => { const [keyword, setKeyword] = useState(initialValue) const onSearch = (value: string) => { const trimmedValue = value.trim() if (trimmedValue.length === 0) { setKeyword("") return } setKeyword(trimmedValue) } const { data } = useSuspenseQuery({ queryKey: ["search", keyword], queryFn, enabled: keyword.length > 0, }) // 未触发搜索时返回对应默认值(示例为数组类型,可根据T的实际类型调整) const safeData = (keyword.length === 0 ? [] : data) as T return { data: safeData, onSearch } }
使用此方法时,需用<Suspense>包裹使用该Hook的组件,处理加载状态。
关于Hook的可用性评估
你当前的Hook存在以下问题,调整后才能正常使用:
- 初始状态崩溃:初始时keyword为空,
data为undefined,直接抛出错误会导致组件崩溃,必须添加加载状态判断或默认值处理。 - 错误处理缺失:未处理请求失败的情况,仅判断
data===undefined抛出错误会掩盖真实的请求错误。 - 搜索逻辑不完善:
onSearch中未处理空输入的清空逻辑,导致keyword可能停留在旧值。
调整后的Hook(如上述两种方案)是可用的,建议根据项目架构选择:
- 若项目已采用Suspense架构,优先选择方法2,类型更安全且代码简洁。
- 若需手动处理加载状态,选择方法1,通过
throwOnError和类型断言确保类型安全,同时暴露isLoading供组件处理加载UI。
内容的提问来源于stack exchange,提问作者dlwhd5717
相关产品推荐
相关产品推荐

