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

Posted

技术标签:

【中文标题】Apollo 本地状态 - 使用未知键查询对象【英文标题】:Apollo local state - querying for object w unknown keys 【发布时间】:2019-11-01 15:04:06 【问题描述】:

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

我一直在查看these docs,但它们的 UI 状态比我想要实现的更简单。

我想移植我在 Redux 应用程序中一直使用的模式,其中许多 UI 元素的值都集中存储。在 Redux 中,我有一个 reducer 对象来存储我的 UI 值,看起来像这样:


  dropdowns: 
    someDropdown: [ index: 0, value: 'Selected Value' ]
  ,
  checkboxes: 
    someCheckbox: true
  

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

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

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


  openDropdownId: 'someDropdown',
  openModalId: null

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

我尝试使用 Apollo Client 重现此内容,但遇到了大量错误。这是我的客户端设置:

例如,一个下拉菜单,其想法是 states 在这里存储打开/关闭状态,而 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;

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

<ApolloProvider client=client>
  <App />
</ApolloProvider>

下面是一个引发错误的查询示例:

const QUERY = gql`
  
    ui @client 
      states
      values
    
  
`;

我看到的错误是:

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

该错误显示在查询组件中。

我还收到两个警告(可能一个针对states,一个针对values):

Missing field __typename in

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


后续问题:如果一个组件有一个 UID,最好能够像这样查询它的值:

const QUERY = gql`
  
    ui @client 
      states 
        $uid
      
      values 
        $uid
      
    
  
`;

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

然而,这会引发错误:

Syntax Error: Invalid number, expected digit but got: "d".

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

【问题讨论】:

【参考方案1】:

我也一直在 apollo 中尝试本地状态管理,所以以下内容有些做作且非常晦涩,但它确实有效。

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

所以这个:

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

例如需要变成这样:

const defaults = 
  ui: 
    __typename: 'UI',
    states: 
      __typename: 'UIStates'
    ,
    values: 
      __typename: 'UIValues'
    
  
;

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

const QUERY = gql`
  
    ui @client 
      states
      values
    
  
`;

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

const QUERY = gql`
  
    ui @client 
      states 
        foo
      
      values 
        bar
      
    
  
`;

其余的取决于您的数据。

如果你需要过滤一个查询——你的查询应该是这样的(第一个返回所有项目,下一个通过 id 过滤一个项目):

const TEST_CLIENT_FILTER_QUERY = gql`
  
    bzz @client 
      id
      title
    
    bzz(id: $id) @client 
      id
      title
    
  
`

您也需要一个解析器。这个很脏,我不确定它是否是 apollo-graphql 方式,但它目前适用于我的目的。

    resolvers: 
      Query: 
        bzz: (root, variables, context) => 
          const key = context.getCacheKey( __typename: 'bzz', id: variables.id )
          return context.cache.extract()[key]
        ,
      ,
    ,

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

  cache.writeData(
    data: 
      bzz: [
        
          __typename: 'bzz',
          id: 1,
          title: 'bzz 1',
        ,
        
          __typename: 'bzz',
          id: 2,
          title: 'bzz 2',
        ,
      ],
    ,
  )

【讨论】:

以上是关于Apollo 本地状态 - 使用未知键查询对象的主要内容,如果未能解决你的问题,请参考以下文章

Apollo 客户端本地状态 - LoggedIn 查询

Apollo 中深度本地状态的 Graphql 查询失败

Apollo 中具有本地状态的变量返回数据

无法使用嵌套值设置 Apollo 本地状态

如何使用 Apollo Query 构造 React 代码,以便随机查询的对象数组不会随着状态变化而重新呈现?

使用 Apollo 在 TypeScript 中填充常量时,对象的类型为“未知”.Vetur(2571)