reactjs - 在@apollo/react-hooks 的 useQuery 钩子中忽略了跳过参数
问题描述
问题:
你好,所以我在我的 ReactJS 应用程序上使用 apollo-client 已经有一段时间了。我刚刚注意到,有时当我使用useQuery
钩子时,执行完全忽略了skip
参数,并继续执行onCompleted
(尽管没有任何数据)。有趣的是,它也不会向我的端点发出 API 请求。但是,如果我只是设置skip
为 false,那么一切正常(如预期的那样)。
此外,每次我使用useQuery
with时都不会发生这种情况skip
,它似乎适用于某些而不是其他。
为什么 apollo 会忽略skip
参数并onCompleted
立即使用空数据执行?有没有修复(除了useLazyQuery
)?
代码示例:
const userQuery = useQuery(GET_USER, {
variables: {
value: userId,
},
skip: true,
onCompleted: props => {
console.log(`props => `, props)
const {
user: { type, role, firstName, lastName, permissions },
} = props;
setValue('firstName', firstName);
setValue('lastName', lastName);
setValue(
'type',
userTypes.find(({ value }) => value === type),
);
setValue(
'role',
userRoles.find(({ value }) => value === role),
);
},
});
补充说明:
• 从 onCompleted 函数记录道具的输出是props => undefined
。
• 我添加skip: true
只是为了证明它实际上不起作用。
• 如果我记录userQuery
自己,那么立即在第一个记录上,userQuery.called
等于 true(但就像我之前所说的,实际上没有执行任何 API 调用)
依赖项
"@apollo/react-hooks": "^3.1.5",
"apollo-cache-inmemory": "^1.6.3",
"apollo-client": "^2.6.10",
"apollo-datasource-rest": "^0.6.6",
"apollo-link": "^1.2.13",
"apollo-link-context": "^1.0.19",
"apollo-link-error": "^1.1.12",
"apollo-link-rest": "^0.7.3",
"apollo-link-retry": "^2.2.15",
"apollo-link-token-refresh": "^0.2.7",
"apollo-upload-client": "^11.0.0",
"react": "16.10.2",
"react-apollo": "^3.1.3",
笔记:
useLazyQuery
似乎工作正常,因此作为一种解决方法,同时您可以结合使用它useEffect
来获得类似的结果。
解决方案
Apollo 客户端有问题。跳过中的错误是一个烦人的错误。你可以放弃 GraphQL,或者解决它们。我建议放弃它,但如果你不能在这里解决它。该模块的工作方式与 useQuery 类似,并且具有跳过工作。它不完整的完整规范,但应该让你开始。
import { useEffect, useState } from 'react';
import { QueryHookOptions, useApolloClient } from '@apollo/react-hooks';
import { ApolloQueryResult, NetworkStatus, QueryOptions, ApolloError } from 'apollo-client';
interface DocumentNode {
loc: {
source: {
body: string;
};
};
}
interface QueryResult<T> extends ApolloQueryResult<T> {
error?: Error | ApolloError;
refetch?: () => void;
}
/**
* Method: useQuery
* Description: enable skip on useQuery. There is a bug that currently ignores it. The bug is confirmed in the 3.2 release as well.
* Note: https://github.com/apollographql/react-apollo/issues/3492
*/
export function useQuery<T>(
query: DocumentNode,
options?: QueryHookOptions
): QueryResult<T | null> {
// Note: using useApolloClient because useLazyQuery fires on initialization. If we are skipping, we don't even want the first fire.
const apolloClient = useApolloClient();
const [result, setQueryResult] = useState<QueryResult<T | null>>({
// Note: initial state
data: null,
loading: false,
stale: false,
networkStatus: NetworkStatus.ready
});
const setResult = (res: QueryResult<T | null>) => {
// Note: GraphQL and Apollo can't decide if they want to return errors, or error in the type contract. I want to be sure the contract is stable. If there are errors, there will be error.
if (res.errors?.length && !res.error) {
[res.error] = res.errors;
}
// Note: Functions should always exist even if the query is not complete.
if (!res.refetch) {
res.refetch = () => {
if (!result.loading) {
execQuery();
}
};
}
setQueryResult(res);
};
const execQuery = async () => {
// Note: loading state. Not spreading "...result" to allow errors to be reset.
setResult({
data: options?.fetchPolicy === 'no-cache' ? null : result.data,
loading: true,
networkStatus: NetworkStatus.loading,
stale: true
});
try {
const queryOptions = ({
...options,
query
} as unknown) as QueryOptions;
await apolloClient
.query(queryOptions)
.then(result => {
setResult(result);
if(options?.onCompleted) options.onCompleted(result.data);
})
.catch(err => {
setResult(err);
if(options?.onError) options.onError(err);
});
} catch (err) {
// Note: fail state
setResult({
...result,
loading: false,
errors: [err],
error: err,
stale: true,
networkStatus: NetworkStatus.error
});
}
};
useEffect(() => {
// Note: Skip Functionality
if (!result.loading && options?.skip !== true) {
execQuery();
}
// Note only listen too explicit variables. If you listen to whole objects they are always different and will cause endless loops.
}, [options?.skip, query.loc.source.body]);
return result;
}
推荐阅读
- angular - 直接输入文本时管理 input[number] 中的最大值和最小值
- python - 我想将我的属性值连接到 GUI 中滑块上的值,但我不断收到属性错误
- node.js - 使用 nodeJS (OAuth2) 执行 http 请求
- python - 检查特定 Linux 命令是否仍在运行的 Python 脚本
- css - 弯曲砌体效果未正确包裹
- sql-server - 我可以在事务期间在单独的事务中运行一些 SQL
- java - 尝试在空对象引用上调用虚拟方法 'android.content.Context android.content.Context.getApplicationContext()'
- ios - 如何在 xamarin.ios 应用程序中显示来自远程 url 的文件
- c# - Winform 文本框绑定 c#
- hadoop - 测量 Hadoop Mapreduce 作业的总运行时间