解决useQuery(ApolloClient)定义新客户端导致的无限循环问题
解决useQuery指定自定义client导致无限循环的问题
你遇到的这个无限循环问题,根源其实很清晰:每次组件渲染时,你都会创建一个全新的ApolloClient实例。useQuery会监听传入的client参数,一旦检测到它是新的对象(引用发生变化),就会重新触发查询;查询触发后组件又会重新渲染,再次创建新的client,如此往复就形成了循环。
下面给你几个可行的修复方案:
方案1:将client实例移到组件外部
把anotherClient的创建代码放在组件函数的外面,这样它只会在应用启动时创建一次,不会随组件渲染重复生成:
// 放在组件函数外面,全局仅创建一次 const anotherClient = new ApolloClient({ uri: "https://my-url/online-service/graphql" }); function YourComponent() { const QueryKTP = gql` query { documents(transactionId:"${transactionId}", input: [ {documentType:"KTP"} ]){ documentResponses{ documentType documentBase64 } responseDescription responseCode message } }` const { data, loading } = useQuery(QueryKTP, {client: anotherClient}); // 组件其他逻辑... }
方案2:用useMemo缓存client实例
如果你的client配置需要依赖组件内部的变量(比如动态uri),可以用useMemo来缓存实例,确保只有当依赖项变化时才重新创建:
function YourComponent() { const QueryKTP = gql` query { documents(transactionId:"${transactionId}", input: [ {documentType:"KTP"} ]){ documentResponses{ documentType documentBase64 } responseDescription responseCode message } }` const anotherClient = useMemo(() => { return new ApolloClient({ uri: "https://my-url/online-service/graphql" }); }, []); // 空依赖数组,仅在组件挂载时创建一次 const { data, loading } = useQuery(QueryKTP, {client: anotherClient}); // 组件其他逻辑... }
额外提醒:你的查询定义也有潜在问题
注意你用模板字符串拼接transactionId到gql查询里,这会导致每次transactionId变化时,生成的QueryKTP都是一个新的GQL对象,同样可能触发不必要的查询。建议改用变量传递的方式:
const QueryKTP = gql` query GetKtpDocument($transactionId: String!) { documents(transactionId: $transactionId, input: [ {documentType:"KTP"} ]){ documentResponses{ documentType documentBase64 } responseDescription responseCode message } } `; // 在useQuery里传入变量 const { data, loading } = useQuery(QueryKTP, { client: anotherClient, variables: { transactionId } });
这种方式不仅更安全(避免注入风险),还能让Apollo更好地缓存查询结果,减少不必要的请求。
内容的提问来源于stack exchange,提问作者Wisnu
相关产品推荐
相关产品推荐

