对于简单的用例,您通常可以依靠默认解析器来获取您需要的数据。但是,要实现过滤缓存中的数据或操作它(就像您对突变所做的那样),您需要编写自己的解析器。要完成您想要做的事情,您可以执行以下操作:
export const resolvers = {
Query: {
todos: (obj, args, ctx) => {
const query = gql`
query GetTodos {
todos @client {
id
text
}
}
`
const { todos } = ctx.cache.readQuery({ query })
return todos.filter(todo => todo.id === args.id)
},
},
Mutation: {},
}
编辑:我们定义的每个类型都有一组字段。当我们返回特定类型(或类型列表)时,该类型上的每个字段都将利用默认解析器来尝试解析自己的值(假设请求了该字段)。默认解析器的工作方式很简单——它查看父(或“根”)对象的值,如果找到与字段名称匹配的属性,则返回该属性的值。如果未找到该属性(或无法强制转换为该字段期望的任何 Scalar 或 Type),则返回 null。
这意味着我们可以,例如,返回一个表示单个 Todo 的对象,并且我们不必为它的id
ortext
字段定义解析器,只要该对象具有id
和text
属性就可以了。换个角度看,如果我们想在Todo
called上创建一个任意字段textWithFoo
,我们可以保持缓存默认值不变,并创建一个解析器,如
(obj, args, ctx) => obj.text + ' and FOO!'
在这种情况下,默认解析器对我们没有好处,因为存储在缓存中的对象没有textWithFoo
属性,所以我们编写自己的解析器。
需要记住的重要一点是,像这样的查询todos
也只是一个字段(在这种情况下,它是查询类型上的一个字段)。它的行为与任何其他字段的行为几乎相同(包括默认解析器行为)。但是,使用apollo-link-state
,您在下定义的数据结构将defaults
成为查询的父值或“根”值。
在您的示例代码中,您defaults
包含一个属性 ( todos
)。因为这是根对象上的一个属性,所以我们可以通过调用查询来获取它,todos
即使没有解析器,仍然可以取回数据。该todos
字段的默认解析器将查看根对象(在本例中为您的缓存),查看名为的属性todos
并返回该属性。
另一方面,像todo
(单数)这样的查询在根(缓存)中没有匹配的属性。您需要为其编写一个解析器以使其返回数据。同样,如果要在查询中返回数据之前对其进行操作(带或不带参数),则需要包含解析器。