Apollo 本地状态 - 查询对象 w 未知键

Sas*_*sha 5 apollo reactjs graphql react-apollo apollo-client

我正在尝试将 Apollo 添加到应用程序中。我将使用它来获取数据,并希望遵循最佳实践并使用新的 API(从 Apollo 2.5 开始)来存储本地 UI 状态。

我一直在查看这些文档,但它们的 UI 状态比我想要实现的更简单。

我想移植我一直在 Redux 应用程序中使用的模式,其中许多 UI 元素的值集中存储。在 Redux 中,我有一个 reducer 对象用于存储我的 UI 值,如下所示:

{
  dropdowns: {
    someDropdown: [{ index: 0, value: 'Selected Value' }]
  },
  checkboxes: {
    someCheckbox: true
  }
}
Run Code Online (Sandbox Code Playgroud)

如在,不同类型的元素被表示为对象,其中每个键是 UI 元素的唯一 ID,值根据元素类型而变化。

我也对上述的扁平化版本持开放态度,其中没有按 UI 元素类型划分的子类别。

我还有一个单独的 reducer 存储一些 UI 元素的状态,例如:

{
  openDropdownId: 'someDropdown',
  openModalId: null
}
Run Code Online (Sandbox Code Playgroud)

至关重要的是,这些数据似乎包括其键不可预测的对象。我既不确定如何使用此类型输入gql,也不确定如何有效地获取此数据(请参阅问题底部)。

我试过用 Apollo Client 重现这个,但遇到了很多错误。这是我的客户端设置:

例如,对于下拉菜单,其想法是在states这里存储 open/closed state ,而values存储有关所选值的信息。

import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import gql from 'graphql-tag';

const typeDefs = gql`
  extend type UI {
    states: Object
    values: Object
  }
`;

const defaults = {
  ui: {
    __typename: 'UI',
    states: {},
    values: {}
  }
};

const cache = new InMemoryCache();
const client = new ApolloClient({
  cache,
  resolvers: {},
  typeDefs
});

console.log({ defaults });
cache.writeData({ data: defaults });

export default client;
Run Code Online (Sandbox Code Playgroud)

然后我像这样使用那个客户端:

<ApolloProvider client={client}>
  <App />
</ApolloProvider>
Run Code Online (Sandbox Code Playgroud)

这是引发错误的查询示例:

const QUERY = gql`
  {
    ui @client {
      states
      values
    }
  }
`;
Run Code Online (Sandbox Code Playgroud)

我看到的错误是:

  • Uncaught Invariant Violation: Missing selection set for object of type undefined returned for query field states

该错误显示在 Query 组件中。

我还收到两个警告(可能一个 forstates一个 for values):

  • Missing field __typename in {}

我是否需要以不同的方式构造我的数据才能像这样查询它?


后续问题:如果一个组件有一个 UID,那么能够查询它的值就好了,比如:

const QUERY = gql`
  {
    ui @client {
      states {
        ${uid}
      }
      values {
        ${uid}
      }
    }
  }
`;
Run Code Online (Sandbox Code Playgroud)

而不是获取所有UI 值,然后在组件中找到合适的值。

但是,这会引发错误:

Syntax Error: Invalid number, expected digit but got: "d".
Run Code Online (Sandbox Code Playgroud)

有没有办法执行这样的查询,或者有更好的方法来处理这一切?虽然这种数据结构可能不符合习惯,但似乎 Apollo 应该支持过滤查询,不是吗?

bst*_*tst 2

我也在 apollo 中尝试了本地状态管理,因此以下内容有些做作且非常晦涩,但它有效。

\n\n

坦率地说 \xe2\x80\x94 所有不是标量或数组的东西都需要有一个类型。

\n\n

所以这:

\n\n
const defaults = {\n  ui: {\n    __typename: 'UI',\n    states: {},\n    values: {}\n  }\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

例如需要变成这样:

\n\n
const defaults = {\n  ui: {\n    __typename: 'UI',\n    states: {\n      __typename: 'UIStates'\n    },\n    values: {\n      __typename: 'UIValues'\n    }\n  }\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

并且在您的查询中必须引用标量或数组,因此您的查询自然不会工作:

\n\n
const QUERY = gql`\n  {\n    ui @client {\n      states\n      values\n    }\n  }\n`;\n
Run Code Online (Sandbox Code Playgroud)\n\n

您需要更深入地定位标量或数组:

\n\n
const QUERY = gql`\n  {\n    ui @client {\n      states {\n        foo\n      }\n      values {\n        bar\n      }\n    }\n  }\n`;\n
Run Code Online (Sandbox Code Playgroud)\n\n

剩下的就看你的数据了。

\n\n

如果您需要过滤查询 \xe2\x80\x94,您的查询将如下所示(第一个查询返回所有项目,下一个查询按 id 过滤项目):

\n\n
const TEST_CLIENT_FILTER_QUERY = gql`\n  {\n    bzz @client {\n      id\n      title\n    }\n    bzz(id: $id) @client {\n      id\n      title\n    }\n  }\n`\n
Run Code Online (Sandbox Code Playgroud)\n\n

您还需要一个解析器。这个非常脏,我不确定这是apollo-graphql方式,但它目前适合我的目的。

\n\n
    resolvers: {\n      Query: {\n        bzz: (root, variables, context) => {\n          const key = context.getCacheKey({ __typename: 'bzz', id: variables.id })\n          return context.cache.extract()[key]\n        },\n      },\n    },\n
Run Code Online (Sandbox Code Playgroud)\n\n

这些是我对此类查询的默认设置:

\n\n
  cache.writeData({\n    data: {\n      bzz: [\n        {\n          __typename: 'bzz',\n          id: 1,\n          title: 'bzz 1',\n        },\n        {\n          __typename: 'bzz',\n          id: 2,\n          title: 'bzz 2',\n        },\n      ],\n    },\n  })\n
Run Code Online (Sandbox Code Playgroud)\n