当前位置: 首页 > 知识库问答 >
问题:

useQuery返回未定义,但返回gql游乐场上的数据

邬浩涆
2023-03-14
"@apollo/react-hooks": "^3.1.3",
"apollo-client": "^2.6.8",

Apollo客户端在react应用程序上返回未定义的数据,但在gql游乐场上返回数据,我不明白为什么它不能在客户端工作,但在graphql游乐场上工作。

图式

我已经为用户查询定义了union,用于错误处理。

type Query {
  user(id: ID!): UserReturn!
}

union UserReturn = User | Error

type User {
  id: ID!
  username: String!
  email: String
  profileUrl: String
  createdAt: Date
  ads: [Doc!]!
}


type Error {
  message: String
  code: ID
}
 async user(_, { id }, { User }) {
    console.log('query - User')
    try {
      await delay(1000 * 3)
      const user = await User.findById(id).populate('userData')
      console.log(user)
      if (!user) return {
        __typename: 'Error',
        message: 'User not found.',
        code: id
      }

      const { _id: id, username, email, createdAt, userData: { profileUrl } } = user

      console.log(username)
      return {
        __typename: 'User',
        id,
        username,
        email,
        createdAt,
        profileUrl
      }
    } catch (err) {
      console.log(err)
      return {
        __typename: 'Error',
        message: 'Something went wrong while getting user.',
        code: LogBack(err, `query/user?id=${id}`, __filename)
      }
    }
  }

 const { data } = useQuery(
    gql`query user($id: ID!) {
      user(id: $id) {
        __typename
        ... on User {
          id
          username
          email
          profileUrl
          createdAt
          # ads
        }
        ... on Error {
          message
          code
        }
      }
    }
    `,
    {
      variables: {
        id: userId
      }
    }
  );

  console.log(data) // undefined

共有1个答案

闾丘德业
2023-03-14

请原谅我,因为这个回答很长。

我也遇到了这个问题。问题似乎发生在使用片段(在本例中是内联)和接口时。通过将正确的内省数据传递给Apollo的启发式片段匹配器,我设法解决了这个问题(请参见步骤3)。

以下是如何解决这个问题的详细的分步指南:

阅读阿波罗的文档,我发现了以下几点:

默认情况下,Apollo客户端的缓存将使用启发式片段匹配器,如果结果包括其选择集中的所有字段,则假定片段匹配;如果缺少任何字段,则假定片段不匹配。这在大多数情况下是有效的,但这也意味着Apollo客户机不能为您检查服务器响应,并且它不能告诉您何时使用updateQuery、updateQuery和writeQuery等手动将无效数据写入存储。此外,当使用带有联合或接口的片段时,启发式片段匹配器将无法准确工作。如果Apollo客户端试图使用带有联合/接口的默认启发式片段匹配器,它将通过控制台警告(开发中)让您知道这一点。IntrospectionFragmentMatcher是使用联合/接口的解决方案,下面将对其进行更详细的解释。

有关v2的更多信息:https://www.apollographql.com/docs/react/v2.6/data/fragments/#fragments-on-union-and-interfaces

为了解决这个问题,我们需要将IntrospectionResultData传递给Apollo客户机(请参见步骤3)。但在此之前,我们需要生成文件或数据。

你有3个选择。手动或自动执行(远程或本地)。

选择下面的一个选项(所有选项最终都是相同的)。在选择一个之前阅读所有的内容。

使用下面的模式来使其适应您自己的模式。注意,下面是打字代码。如果使用普通JS,请删除类型

请注意,在我的例子中,我在我的.gql文件中有一个联合类型,其方式如下:

   # GraphQL code omitted. 
  union PlanningResult = Planning | PlanningTechnical
// For Apollo V 2.x
export interface IntrospectionResultData {
  __schema: {
    types: {
      kind: string;
      name: string;
      possibleTypes: {
        name: string;
      }[];
    }[];
  };
}

const result: IntrospectionResultData = {
  __schema: {
    types: [
      {
        kind: 'UNION',
        name: 'PlanningResult',
        possibleTypes: [
          {
            name: 'Planning',
          },
          {
            name: 'PlanningTechnical',
          },
        ],
      },
    ],
  },
};
export default result;

// For Apollo V3:

      export interface PossibleTypesResultData {
        possibleTypes: {
          [key: string]: string[]
        }
      }
      const result: PossibleTypesResultData = {
  "possibleTypes": {
    "PlanningResult": [
      "Planning",
      "PlanningTechnical"
    ]
  }
};
      export default result;
    

一旦你完成了这一点,就进行第3步。

// This is for V2 only, for V3 use the link down below (They're not the same!).

// For V2: https://www.apollographql.com/docs/react/v2.6/data/fragments/#fragments-on-unions-and-interfaces
// For V3 please, go to https://www.apollographql.com/docs/react/data/fragments/#generating-possibletypes-automatically

const fetch = require('node-fetch');
const fs = require('fs');

fetch(`${YOUR_API_HOST}/graphql`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    variables: {},
    query: `
      {
        __schema {
          types {
            kind
            name
            possibleTypes {
              name
            }
          }
        }
      }
    `,
  }),
})
  .then(result => result.json())
  .then(result => {
    // here we're filtering out any type information unrelated to unions or interfaces
    const filteredData = result.data.__schema.types.filter(
      type => type.possibleTypes !== null,
    );
    result.data.__schema.types = filteredData;
    fs.writeFile('./fragmentTypes.json', JSON.stringify(result.data), err => {
      if (err) {
        console.error('Error writing fragmentTypes file', err);
      } else {
        console.log('Fragment types successfully extracted!');
      }
    });
  });

转到后端代码或graphql.gql文件所在的任何地方,并执行以下操作:

  1. 安装GraphQL代码生成器:
yarn add graphql

yarn add -D @graphql-codegen/cli
yarn graphql-codegen init
  • 后端-API或服务器,用React构建的应用程序
  • 您的模式在哪里?./appsync/appsync.gql
  • 选择插件:片段匹配器(也可以选择其他插件...这是重要的一个!)
  • 文档:./appsync/generated/introspection.ts(这是您希望输出文件的地方)
overwrite: true
schema: "./appsync/appSync.gql"
# documents: "./appsync/**/*.gql"
generates:
  ./appsync/generated/introspection.ts:
    plugins:
      # - "typescript"
      # - "typescript-operations"
      # - "typescript-resolvers"
      # - "typescript-react-apollo"
      - "fragment-matcher"
    config:
    # NOTE: Remember to specify the CORRECT Apollo Client Version
      apolloClientVersion: 2.6
  ./graphql.schema.json:
    plugins:
      - "introspection"

然后(非常重要!)运行:

yarn install

因为向导将包添加到我们的package.json中。

然后,生成代码:

yarn generate
For V2:
import ApolloClient from 'apollo-client/ApolloClient';
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import { InMemoryCache } from 'apollo-cache-inmemory/lib/inMemoryCache';
// The file we just generated. If it's a .json file 
// remember to include the .json extension
import introspectionQueryResultData from './apollo/fragmentTypes';

const fragmentMatcher = new IntrospectionFragmentMatcher({
  introspectionQueryResultData,
});

export const globalClient = new ApolloClient({
  link,
  cache: new InMemoryCache({ fragmentMatcher }),
});

For V3:
import { InMemoryCache, ApolloClient } from '@apollo/client';
// In case you used graphql-code-generator
// import introspectionQueryResultData from './apollo/fragmentTypes';
// The file we just generated. If it's a .json file 
// remember to include the .json extension
import possibleTypes from './path/to/possibleTypes.json';

const cache = new InMemoryCache({
  possibleTypes,
});
const client = new ApolloClient({
  // ...other arguments...
  cache,
});
 类似资料:
  • 问题内容: 因此,当我打开灯箱时,我试图禁止在页面上滚动,而我发现这个确实有用的脚本非常有用。不幸的是,当我在自己的页面上使用它时,它也禁止在灯箱中滚动。我开始用警报调试代码,只是发现该事件。wheelDelta在我的页面上返回“undefined”,而在JSFiddle中,它返回-120。 问题答案: jQuery事件处理程序中的对象不能反映真实事件。是IE和Opera的非标准事件属性,可通过j

  • 我正在尝试为discord bot执行命令,它从MySQL表中输出整数。 我尝试使用async/await、Promissions和回调来实现这一点,但结果总是一样的。在这里,我用promise再次尝试,因为在过去它不知何故起了作用。现在不会了。 下面是返回promise的函数: 下面的代码将结果赋值给Access Level变量: Catch函数捕获表示“TypeError:无法读取未定义的属性

  • 我的授权码请求: 我正在用这个得到授权码。但是每当我使用此代码发送access_token请求时,我都会得到一个错误。(代码400)

  • 我正在使用下面的gql查询生成一个GraphQL请求。 但是当我在下面的代码中注销它时,它返回未定义的。 知道我做错了什么吗?该怎么纠正?

  • 我是JS的新手,不明白为什么我的程序中的图像没有改变。所有的变量都运行良好。下面是片段 所有的图像都被命名为1.jpg,2.jpg,3.jpg,4.jpg,直到24。这是一种很奇怪的方式,我也知道,如果有人知道更好的方式,那会更好。