首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在@apollo/ useQuery -hooks的react钩子中忽略了跳过参数

在@apollo/ useQuery -hooks的react钩子中忽略了跳过参数
EN

Stack Overflow用户
提问于 2020-05-20 20:07:01
回答 1查看 4.1K关注 0票数 5

问题是:

您好,我已经在我的ReactJS应用程序上使用了一段时间的阿波罗客户端。我刚刚注意到,有时当我使用useQuery钩子时,执行完全忽略skip参数,而只是继续执行onCompleted (尽管没有任何数据)。有趣的是,它也不向我的端点发出API请求。但是,如果我只是将skip设置为false,那么一切都会正常工作(正如预期的那样)。

而且,这并不是我每次在skip中使用useQuery时都会发生的,它似乎在一些上有效,而在另一些上无效。

为什么apollo忽略skip参数,只使用空数据立即执行onCompleted?有没有修复方法(除了useLazyQuery)?

代码示例:

代码语言:javascript
运行
复制
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调用)

依赖关系

代码语言:javascript
运行
复制
"@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结合使用以获得类似的结果。

EN

回答 1

Stack Overflow用户

发布于 2021-02-17 08:28:13

Apollo客户端有问题。skip中的bug是一个令人讨厌的bug。你可以放弃GraphQL,或者绕过它们。我建议放弃它,但是如果你不能,这里有一个替代方法。此模块的工作方式与useQuery类似,并具有跳过功能。对于完整的规范来说,这是不完整的,但应该可以帮助您入门。

代码语言:javascript
运行
复制
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;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61912720

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档