【问题标题】:Apollo on local client doesn't trigger the local resolvers本地客户端上的 Apollo 不会触发本地解析器
【发布时间】:2020-08-27 10:18:46
【问题描述】:

在本地状态客户端(前端本地状态)的情况下,Apollo 不会触发解析器。阿波罗 2.7

有人知道为什么会这样吗?

设置如下:

阿波罗客户端

import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http'
import fetch from 'isomorphic-unfetch'

import { resolvers, typeDefs } from './resolvers';
import { initCache } from './init-cache';

export default function createApolloClient(initialState, ctx) {
  // The `ctx` (NextPageContext) will only be present on the server.
  // use it to extract auth headers (ctx.req) or similar.
  return new ApolloClient({
    ssrMode: Boolean(ctx),
    link: new HttpLink({
      uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', // Server URL (must be absolute)
      credentials: 'include', // Additional fetch() options like `credentials` or `headers`
      fetch,
    }),
    typeDefs,
    resolvers,
    connectToDevTools: true,
    cache: initCache({
                   robot: {
                     __typename: 'Robot',
                     name: 'Robbie',
                     status: 'live',
                    },

                  member: {
                     __typename: 'Member',
                     name: 'RFesagfd',
                     }
                   }),
     })
  }

类型和解析器 (resolvers.js)

import gql from 'graphql-tag';

export const typeDefs = gql`
  type Robot {
    name: String!
    status: String!
  }

  type Member {
    name: String!
    isLogged: Boolean!
  }

`;

export const resolvers = {
  Member: {
    isLogged: (...args) => {
      console.log('args', args); // THIS NEVER TRIGGERS SOMEHOW
      return true;
    }
  }
};

查询

const GET_IS_MEMBER_LOGGED = gql`
  query isMemberLogged {
    member @client {
      name
      isLogged
    }
  }
`;

感谢您的帮助!

【问题讨论】:

  • export const resolvers = { member: { - member 小写? ...并且您需要为整个成员提供解析器
  • 嗨 xadm。谢谢你的帮助。 Member 是一种类型,因此它不应该像查询解析器那样被喜欢。请你给我看一下完整成员解析器的例子吗?我以为我做对了

标签: graphql apollo


【解决方案1】:

您需要定义本地查询的结果类型:

const typeDefs = gql`
  extend type Query {
    robot: Robot
    member: Member
  }

...和查询的解析器 - 不是类型(因为您将整个查询装饰为本地)...但是您必须返回输入的数据:: p>

export const resolvers = {
  Query: {
    member: (...args) => {
      console.log('args', args); 
      return {
        __typename: 'Member',
        name: 'some name', // read from cache
        isLogged: true // function result
      };
    }
  }
};

您还应该使用__typename 进行缓存写入。

更新

假设您在缓存中有一个成员...您可以:

// read (initialized with permanent) data:
const memberData = cache.readQuery(....
// f.e. it should have `__typename` and 'name`
// ... and 'decorate' it with derived properites
memberData.age = currentYear - memberData.birthYear;
memberData.isLogged = someFuncReturningBool();
return memberData; // Member type shaped object

这是关于形状/数据组织 - 类型化(返回具有定义属性的类型形状对象)或简单(单独返回所有属性)或混合,例如(一些全局应用状态)

const GET_IS_MEMBER_LOGGED = gql`
  query profileViewData {
    member @client {
      name
      isLogged
    }
    isProfilePanelOpen @client
    termsAccepted @client
  }
`;

【讨论】:

  • 如果我想在缓存中有一个预定义的初始成员模型并且我想有一些不应该出现在缓存中但应该是的计算字段怎么办?由从成员缓存中获取一些值并生成这些新字段的解析器提供?例如。全名。如何实现?如果我已经在缓存中有一个成员查询解析器并且我想要的只是一些额外的“计算”字段,我应该有一个成员查询解析器吗?
  • 谢谢xadm。这是一个很酷的解决方案,看起来它可能会起作用。但同样,是否有一种方法可以为此类字段创建解析器,而无需执行 Query -> Member 解析器?我想保持这些东西干净和分开。例如:对初始缓存中不存在的对象(动态生成)使用查询解析器,对初始缓存中的现有对象使用不存在字段的解析器。
  • "默认情况下,基于@client 的字段以与远程字段完全相同的方式利用缓存。本地解析器运行后,其结果与任何远程结果一起缓存。" - 缓存的数据必须是键入,没有“不存在的字段”情况(缓存写入时忽略其他字段 - 就像在远程服务器上一样,解析器可以返回更多但响应被过滤为类型/请求形状)......但是你可以使用 customJSON 类型(阅读文档)来存储(和读取)某个对象中的任何内容。
【解决方案2】:

我找到了一个可能的解决方案。也许这些信息对某人有用。 如果我们想省略查询解析器 + 字段解析器,并且我们想要拥有唯一的字段解析器,我们需要使用 @client(always: true)

深入解释

一般来说,Apollo 客户端如何使用 Cache 存在问题。 默认情况下,它会缓存响应,下次它会从缓存中获取缓存的结果(例如optimistic UI)。即使在客户端的情况下,此行为也是相同的。

这意味着当我们在缓存中有初始模型时,Apollo 将从缓存中获取并忽略解析器,即使我们传递了@client 指令。 为了解决这个问题并让 Apollo 知道我们需要使用本地解析器,即使我们有缓存的对象,我们也需要对首选字段或整个对象使用 @client(always: true)。我在下面做了一个例子。

附言不幸的是,我没有找到如何强制 Apollo 使用不存在的字段,所以如果我们想为特定字段提供一些解析器,我们仍然需要将初始字段值定义为初始缓存模型,让 Apollo 知道这个领域。之后,感谢 @client(always: true),Apollo 将使用解析器为该特定字段生成一些高计算输出。
一般来说,没关系,因为我们应该知道我们的模型中会有什么样的动态场。

阿波罗客户端

import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http'
import fetch from 'isomorphic-unfetch'

import { resolvers, typeDefs } from './resolvers';
import { initCache } from './init-cache';

export default function createApolloClient(initialState, ctx) {
  // The `ctx` (NextPageContext) will only be present on the server.
  // use it to extract auth headers (ctx.req) or similar.
  return new ApolloClient({
    ssrMode: Boolean(ctx),
    link: new HttpLink({
      uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', // Server URL (must be absolute)
      credentials: 'include', // Additional fetch() options like `credentials` or `headers`
      fetch,
    }),
    typeDefs,
    resolvers,
    connectToDevTools: true,
    cache: initCache({
                     author: {
                     __typename: 'Author',
                     posts: 0,
                     name: '' // NEED TO SET AN INITIAL VALUE
                     }
     })
  }

类型和解析器 (resolvers.js)

import gql from 'graphql-tag';
import { print  } from 'graphql';

export const typeDefs = gql`
  type Author {
    posts: Int!
    name: String
  }

`;


export const resolvers = {
  Author: {
    name(author) {
      console.log('Author name resolver', author). // WORKS
      return 'NAME';
    },
  },

};

查询

const GET_AUTHOR = gql`
  query getAuthor {
    author {
      posts
      name @client(always: true)
    }
  }
`;

【讨论】:

    猜你喜欢
    • 2020-01-31
    • 2020-02-05
    • 2020-01-23
    • 2020-07-22
    • 2020-03-06
    • 2020-10-26
    • 2020-02-15
    • 2020-05-03
    • 1970-01-01
    相关资源
    最近更新 更多